目录
- Linux正则三剑客
- grep,擅长单纯的查找或匹配文本内容;
- sed,擅长文本编辑,处理匹配到的文本内容;
- awk,适合格式化文本文件,对文本文件进行更复杂的加工处理、分析。
awk [option] ‘pattern[action]’ file
awk 参数 模式和操作 被处理文件
*action 是指动作,awk擅长文本格式化,且能输出格式化后的结果,因此最常用的动作就是 print 和 printf
-
- awk处理文本内容模式
- awk默认以空格为分隔符,且多个空格也识别为一个空格,作为分隔符;
- awk按行处理文件,一行处理完毕之后,再处理下一行;
- awk可以根据用户指定的分隔符去工作,没有指定,则默认为空格
- awk处理文本内容模式
- awk 参数
选项 | 含义 |
-F fs | 指定以 fs 作为输入行的分隔符,awk 命令默认分隔符为空格或制表符。 |
-v var=val | 在执行处理过程之前,设置一个变量 var,并给其设备初始值为 val。 |
-f file | 从脚本文件中读取 awk 脚本指令,以取代直接在命令行中输入指令。 |
…… | 还有很多其他的参数,不做讲解。 |
-F 例:
-v 例:
-f 例:
- awk 模式和操作
awk脚本是由模式和操作组成的:
pattern {action}
两者是可选的,如果没有模式,则action应用到全部记录,如果没有action,则输出匹配全部记录。默认情况下,每一个输入行都是一条记录,但用户可通过RS变量指定不同的分隔符进行分隔。
模式可以是以下任意一个:
-
-
- /正则表达式/:使用通配符的扩展集。
- 关系表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较,如$2>%1选择第二个字段比第一个字段长的行。
- 模式匹配表达式:用运算符~(匹配)和~!(不匹配)。
- 模式,模式:指定一个行的范围。该语法不能包括BEGIN和END模式。
- BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。
- END:让用户在最后一条输入记录被读取之后发生的动作。
-
特殊模式—BEGIN & END:
通常使用BEGIN在循环文件之前设置变量;
使用END来输出最终结果。
因此,如果只想赋值一次、打印变量或文本一次,就在BEGIN 或 END中写。
如果想要循环多少行就打印多少次,就不要在BEGIN 或 END中写,这也是awk的常规用法。
如:
操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内。主要有四部份:
- 变量或数组赋值
- 输出命令
- 内置函数
- 控制流命令 (while /for/if等)
- awk 内置环境变量
变量 | 描述 |
$n | 当前记录的第n个字段,字段间由FS分隔。 |
$0 | 完整的输入记录。 |
ARGC | 命令行参数的数目。 |
ARGIND | 命令行中当前文件的位置(从0开始算)。 |
ARGV | 包含命令行参数的数组。 |
CONVFMT | 数字转换格式(默认值为%.6g) |
ENVIRON | 环境变量关联数组。 |
ERRNO | 最后一个系统错误的描述。 |
FIELDWIDTHS | 字段宽度列表(用空格键分隔)。 |
FILENAME | 当前文件名。 |
FNR | 同NR,但相对于当前文件。 |
FS | 字段分隔符(默认是任何空格)。 |
IGNORECASE | 如果为真,则进行忽略大小写的匹配。 |
NF | 当前记录中的字段数。 |
NR | 当前记录数。 |
OFMT | 数字的输出格式(默认值是%.6g)。 |
OFS | 输出字段分隔符(默认值是一个空格)。 |
ORS | 输出记录分隔符(默认值是一个换行符)。 |
RLENGTH | 由match函数所匹配的字符串的长度。 |
RS | 记录分隔符(默认是一个换行符)。 |
RSTART | 由match函数所匹配的字符串的第一个位置。 |
SUBSEP | 数组下标分隔符(默认值是\034)。 |
- awk 运算符
运算符 | 描述 |
= += -= *= /= %= ^= **= | 赋值 |
?: | C条件表达式 |
|| | 逻辑或 |
&& | 逻辑与 |
~ ~! | 匹配正则表达式和不匹配正则表达式 |
< <= > >= != == | 关系运算符 |
空格 | 连接 |
+ - | 加,减 |
* / & | 乘,除与求余 |
+ - ! | 一元加,减和逻辑非 |
^ *** | 求幂 |
++ -- | 增加或减少,作为前缀或后缀 |
$ | 字段引用 |
in | 数组成员 |
- awk 函数
在默认情况下,awk支持从文件或者STDIN中读取数据。我们也可以使用getline来灵活读取数据,例如在main代码块执行过程中读取某个非待处理文件的数据,或者从某个读取某个shell命令结果数据。
getline有返回值:
- 1:正确读取到了数据。
- 0:读取数据遇到EOF。
- 负数:读取遇到了错误。-1表示文件无法打开,-2表示IO操作需要重试。遇到错误时还会使用变量ERRNO来描述错误。
为了awk代码的健壮性,在使用getline的时候,一般会加上条件判断。
在循环逐行匹配,如果遇到next,就会跳过当前行,直接忽略下面语句,而进行下一行匹配。
gsub
是 AWK 中的一个函数,用于全局替换字符串中的子字符串。以下是 gsub
函数的语法:
gsub( regexp, replacement, target)
其中,regexp
表示要替换的字符串模式,可以是一个正则表达式;replacement
表示替换目标字符串的新内容;target
表示要操作的目标字符串。
如何将常见的FIO grouping输出,如下:
格式化输出为:
printf "%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\n" "rw_type" "iops(k)" "lat(usec)" "p99(usec)" "p999(usec)" "p9999(usec)" "usr" "sys" "bw"
cat $file | awk '{if(/read:/) {while(!/iops.*:/){preline=$0;getline;print preline}};if(/write:/) {while(!/iops.*:/){lastline=$0;getline;print lastline}};if(/READ:/)print $3;if (/WRITE:/)print $3;if (/cpu.*:/)print $3,$4}' |sed 's/IOPS=\|,\|(\|)\|\|\|\[\|\]\||\|avg=\|usr=\|sys=//g'|sed 's/th=/ /g'|awk '{if(/clat per.*/)print $3;if (/read:/)print $2;if(/write:/)print $2;if(/99\.00/) print;if(/99\.99/)print;if(/^[0-9].*%/)print;if(/MB\/s$/)print;if(/clat.*sec/)print $2,$5}'|awk '{if (NR==1) { if(/k/)iops=$1; else iops=$1/1000};if(NR==2){if(/usec/)lat=$2;else lat=$2/1000};if (NR==3) {if(/usec/) nsec=1;else nsec=1000};if (NR==5){if(/99\.00/){p99=$2/nsec;p999=$6/nsec}};if(NR==6){if(/99\.99/){p9999=$2/nsec}};if(NR==7){usr=$1;sys=$2};if (NR==8){bw=$1;printf "%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\n","read",iops,lat,p99,p999,p9999,usr,sys,bw}}'