项目中需要一个统计接口量的脚本,于是尝试着写了第一个awk脚本。
过程不轻松,但是写完了觉得很爽。哈哈
-----------------------------------------------------------------------------------------------------------------------------------
######################################### ####思路: ####1 按行读取,需要判断每条记录的归属线程,并缓存起来, ####2 每个线程的记录打印都是有顺序的,输入报文>异常>输出报文 ####3 将输入报文覆盖缓存,当第一次读取到Exception时,认为异常开始,将最近一次的输入报文打印, ####4 异常全部打印完毕后,打印输入报文 ####注意: ####所有的缓存都是按照线程名称做得,类似于线程变量,互不影响,通过数组实现 #### ####使用: ####1 THREAD_KEY需要替换,不同的日志不一样 ####2 INPUT_KEY和OUTPUT_KEY如不同也替换 ####3 isExclude函数,如有需要可以修改不同的排除条件 ######################################### BEGIN{ # 变量是不带双引号的,变量值需要带着双引号 THREAD_KEY = "@HttpThreadPool"; INPUT_KEY = "输入报文"; OUTPUT_KEY = "输出报文"; ROW_CACHE = "ROW_CACHE"; THREAD_NAME = "THREAD_NAME"; FILE_NAME = "XXXXX"; } #获取线程名 function getThreadName(str){ # 线程名称开始索引 THREAD_KEY_END_INDEX = index($0, THREAD_KEY); if(THREAD_KEY_END_INDEX > 0){ # 获取线程名称 THREAD_NAME_T = substr($0, THREAD_KEY_END_INDEX - 9, 9 ); if(THREAD_NAME_T != "") { THREAD_NAME= THREAD_NAME_T; } } return THREAD_NAME; } #判断此行是否需要排除,后续可增加条件 function isExclude(str){ return index(str, "通过HTTP方式获取缓存失败"); } #判断不需打印输入输出报文的异常 function needRequestMsg(str){ return index(str, "未找到相应文件") + index(str, "没有生成密钥"); } { if(FILE_NAME != FILENAME){ if(FILE_NAME != "XXXXX" ){ printf("+++++++++++++++++文件处理完成[%s]+++++++++++++++++++\n", FILE_NAME); } printf("+++++++++++++++++开始处理文件[%s]+++++++++++++++++++\n", FILENAME); FILE_NAME = FILENAME; } # 获取线程名 THREAD_NAME = getThreadName($0); # 处理不需要打印输入输出报文的部分 if(needRequestMsg($0) > 0){ printf("---------Begin Exception-%s-[%d]------------\n", THREAD_NAME, ++THREAD_EXCEPTION_NUM[THREAD_NAME]); printf("%s\n", ROW_CACHE); printf("%s\n", $0); getline ; while (index($0, "at ") > 0 && index($0, "(") > 0 ){ printf("%s\n", $0); getline; } printf("---------End Exception-%s-[%d]------------\n", THREAD_NAME, THREAD_EXCEPTION_NUM[THREAD_NAME]); } # 当此行中有关键字Exception if(index($0, "Exception") > 0 && isExclude($0) == 0) { # BEGIN_EXCEPTION_FLAG是一个key为线程名称的数组缓存,记录当前线程是否开始一个Exception if((BEGIN_EXCEPTION_FLAG[THREAD_NAME] == "" || BEGIN_EXCEPTION_FLAG[THREAD_NAME] == "0")){ # 当没有开始时,将缓存的输入报文打印,同时记录状态为已开始 BEGIN_EXCEPTION_FLAG[THREAD_NAME] = "1"; } # 当此行没有线程名称,且不存在Caused by关键字时,说明为异常被换行,打印上一行 if(index($0, THREAD_NAME) == 0 && index($0, "Caused") == 0 && index($0, "at ") == 0){ BODY_EXCEPTION[THREAD_NAME] = sprintf("%s\n%s", BODY_EXCEPTION[THREAD_NAME], ROW_CACHE); } # 所有Exception的行都打印 BODY_EXCEPTION[THREAD_NAME] = sprintf("%s\n%s", BODY_EXCEPTION[THREAD_NAME], $0); } # 存在关键字"at "的行打印 if(index($0, "at ") > 0 && index($0, "(") > 0){ BODY_EXCEPTION[THREAD_NAME] = sprintf("%s\n%s", BODY_EXCEPTION[THREAD_NAME], $0); } # 当此行中存在输出报文关键字,且已经开始一个Exception,打印输入报文,Exception体,输出报文 if(index($0, OUTPUT_KEY) > 0 && BEGIN_EXCEPTION_FLAG[THREAD_NAME] == "1"){ printf("---------Begin Exception-%s-[%d]------------\n", THREAD_NAME, ++THREAD_EXCEPTION_NUM[THREAD_NAME]); printf("%s\n", INPUT_MSG[THREAD_NAME]); printf("%s\n", BODY_EXCEPTION[THREAD_NAME]); # 有可能输出报文有换行,目前处理换行一次的情况,判断行尾是"?>"时,读取下一行并打印 printf("%s", $0); if(substr($0, length($0)-1) == "?>"){ getline t; printf("%s\n", t); } else { print "\n"; } printf("---------End Exception-%s-[%d]------------\n", THREAD_NAME, THREAD_EXCEPTION_NUM[THREAD_NAME]); # 输出报文已打印,Exception结束 BEGIN_EXCEPTION_FLAG[THREAD_NAME] = "0"; BODY_EXCEPTION[THREAD_NAME] = ""; INPUT_MSG[THREAD_NAME] = ""; } # 当此行中存在输入报文关键字时 if(index($0, INPUT_KEY) > 0){ # 缓存此行,并判断是否存在报文换行的情况 INPUT_MSG[THREAD_NAME] = $0; if(substr($0, length($0)-1) == "?>"){ getline t; INPUT_MSG[THREAD_NAME] = sprintf("%s%s", INPUT_MSG[THREAD_NAME], t); } } # 缓存当前行 ROW_CACHE = $0; } END{ printf("+++++++++++++++++文件处理完成[%s]+++++++++++++++++++\n", FILENAME); }
相关推荐
**第一章:概述** 本章将介绍AWK的基本概念,包括它的起源、用途以及与其他文本处理工具(如grep、sed)的区别。AWK的工作原理是逐行扫描输入文件,对每一行执行一系列预定义的动作。这一特性使得AWK非常适合处理...
如果想打印出第一个和第三个字段,可以使用`'{ print $1 $3 }'`,但请注意,相邻的字符串不会自动添加空格,需要显式地插入,如`'{ print $1 " " $3 }'`。 在AWK中,字段可以通过数字索引引用,如`$1`、`$2`等,也...
这里`$1`表示第一个字段,`$2`表示第二个字段,以此类推。 **三、模式匹配** AWK支持两种模式匹配:行模式和记录模式。行模式基于行内容进行匹配,如: ```awk /regex/ { action } ``` 记录模式则基于行号或其他...
- `-F`选项可以指定分隔符,如`awk -F":" '{print $1}' /etc/passwd`会打印`/etc/passwd`文件中每一行的第一个字段,即用户名。 - `$1`、`$3`等表示字段,多个连续的空格或制表符被视为一个分隔符。 - 若要合并字段...
例如,`plot 'datafile' using 1:2 with lines`将根据"datafile"中的第一列作为x轴,第二列作为y轴绘制线条图。 在NS2仿真的整个流程中,TCL脚本定义了网络行为,AWK处理了输出的数据,而GNUPLOT则将这些数据转化为...
### 第二十四章:Shell 脚本 - 正则、grep、sed、awk 三剑客 #### 一、正则表达式及 grep **1. 概述** 正则表达式是一种强大的文本处理工具,它能够帮助用户方便地进行字符串的搜索、替换等操作。在 Linux 系统中...
- 使用AWK可以方便地处理文件中的特定字段,如`print $1,$2`表示打印第一和第二个字段。 - 支持脚本形式的AWK,通过`-f`选项指定脚本文件,如`awk -f test.awk /etc/passwd`。 3. **条件判断与循环** - AWK支持...
这里的模式是默认的(即每一行),动作是打印第一个字段 `$1`。 ### 3. 域与记录 在 `awk` 中,文本被分割成记录(通常是行)和域(由分隔符分开的部分)。如果没有指定 `-F`,默认的分隔符是空格或制表符。例如,...
使用`$n`来引用域,如`$1`代表第一个域,`$0`代表整个记录。`print`命令常用于输出域内容,例如`print $0`打印整行,`print $1,$4`打印第一个和第四个域。 4. **动作和输出管理** - `print`命令可以输出指定的域,...
例如,"BEGIN"模式在处理任何输入前执行,"END"模式在处理完所有输入后执行,而"{print $1}"这样的模式-动作对会打印每行的第一个字段。 awk还提供了内置变量,如NR(已读取的行数)、NF(当前行的字段数)和FS...
例如,`print $1`会打印每一行的第一个字段。 3. **条件测试**:awk支持条件语句如`if...else`,可以根据某个条件执行不同的动作。例如,`if ($2 > 10) {print $0}`会打印所有第二个字段大于10的行。 4. **循环...
例如`awk -F ":" '{print $1}' /etc/passwd`会打印出/etc/passwd文件中每一行的第一个字段。 - **连接字段**:可以通过直接连接字符串的方式输出多个字段。例如`awk -F ":" '{print $1 $3}' /etc/passwd`将输出...
- **分解记录**:使用内置变量`NF`表示当前记录的字段数量,`$n`引用第n个字段,如`$1`是第一个字段,`$0`代表整个记录。 3. **输出** - **print**:AWK中最常用的输出函数,用于打印字段或表达式的结果,默认用...
例如,`awk -F ',' '{print $1}' file.csv`会打印`file.csv`中所有行的第一列,其中`-F ','`设定了字段分隔符为逗号。 结合这两个工具,开发者可以在Shell脚本中实现更复杂的数据处理任务。例如,可以先用`sed`...
基本形式为`awk 'program' file1 file2 ...`,其中`program`是AWK脚本。 4. **AWK的语法**: - `pattern {action}`是AWK的基本结构,表示当行匹配`pattern`时执行`action`。 - 如果没有指定`pattern`,则`action`...
《SED与AWK 高清第三版》是一本专注于Linux系统中强大文本处理工具sed和awk的教程。在Linux环境中,sed和awk是不可或缺的工具,它们能够高效地处理大量文本数据,进行搜索、替换、格式化等操作,极大地提高了运维...
1. **日志文件分析**: awk经常用于分析和处理大量的日志文件,帮助快速查找特定的信息或统计关键数据。 2. **配置文件处理**: 对于需要解析和修改的配置文件,awk能够轻松实现自动化处理。 3. **文本数据处理**: 如...
- `[ABC][DEF]`:两个方括号表示前后两个字符都要匹配,第一个是`[ABC]`的任何一个,第二个是`[DEF]`的任何一个。 2. **AWK算术运算符** - `^`或`**`:幂运算,例如`2^3`等于8。 - `%`:求模运算,如`7%3`等于1...