awk(gawk)

时间:2021-08-27 00:21:55

  awk,逐行处理文本内容。Linux里的awk其实是“gawk”。

  使用格式:

    awk [选项] '模式匹配 {命令 命令参数}' file1, file2, ……

支持的选项 说明

-f program-file

--file program-file

从文件接收 awk指令,可以同时指定多个文件

-F fs

--field-separator fs

指定(fs)列分隔符

-v var=value

--assign var=value

为 BEGIN 块定义变量var,指定其值为value

-d[file]

--dump-variables[=file]

 

  demo,ipaddress俩文件的内容是环网柜、柱上开关柜的主、备ip地址。分别以制表符、冒号分割。

$ cat demo
RingNetwork 181.36.1.8 182.36.4.8
Switch 181.32.1.22 182.36.4.42
Switch 181.32.1.23 182.36.4.43
$ cat ipaddress
R:181.36.1.8:182.36.4.8
S:181.32.1.22:182.36.4.42
S:181.32.1.23:182.36.4.43

  命令:

    print  打印输出,参数之间使用逗号分隔。

    printf  输出时,需要指定输出格式。

printf 输出格式铆定符
格式
铆定符
效果说明 例子(页面最下边)
%c 打印成 ascii 码表的“char”形式 2.1
%s 输出字符串 2.2
%d, %i 十进制数的整数部分 2.3
%o 无符号八进制数的整数部分 2.4
%x, %X 同上,大小的区别表示[a-f],[A-F] 2.5
%u 无符号的十进制数的整数部分  
%f 浮点数 2.6
%% 输出%,相当于\\输出反斜线一样  
%10s 预留10个字符位置,右对齐  
%-10s 左对齐显示  

  常见变量:

    FS  输入列分割符

    OFS  输出列分隔符

    RS  输入行分割符

    ORS  输出行分割符

    NF  记录数(当前处理的)

    NR  行数(当前处理)

    FNR  行数(当前文件)


1 输出文本 print

1.1 输出指定列信息

  取出每个设备的主ip地址信息

$ awk '{print $2}' demo
181.36.1.8
181.32.1.22
181.32.1.23

1.2 列分隔符

1.2.1 列的引用表示

  $1、$2……分别表示当前处理行的第一列、第2列……。$0表示当前行所有列。

$ awk '{print $0}' demo
RingNetwork 181.36.1.8 182.36.4.8
Switch 181.32.1.22 182.36.4.42
Switch 181.32.1.23 182.36.4.43
$ awk '{print $1,$2,$3}' demo
RingNetwork 181.36.1.8 182.36.4.8
Switch 181.32.1.22 182.36.4.42
Switch 181.32.1.23 182.36.4.43

  输出awk处理的文件的列数。

$ awk '{print NF}' demo

$ awk '{print NF}' ipaddress

$ awk '{print NF}' demo ipaddress

1.2.2 输出列分割符

  awk默认输出分隔符是空格,可以通过变量“OFS”修改,需要使用双引号。

$ awk 'BEGIN{OFS=":"} {print $1,$2,$3}' demo
RingNetwork:181.36.1.8:182.36.4.8
Switch:181.32.1.22:182.36.4.42
Switch:181.32.1.23:182.36.4.43

1.2.3 输入列分割符

  awk以空白符作为默认输入分割符,就算分割不是制表符,而是某些个空格符也一样能准确取到主ip。同时,还可以修改默认输入分割符,通过变量“FS”显式指定分割符为空格。

 awk 'BEGIN{FS=":"} {print $1,$2,$3}' ipaddress
R 181.36.1.8 182.36.4.8
S 181.32.1.22 182.36.4.42
S 181.32.1.23 182.36.4.43

  或者在选项“F”里指定分隔符。

$ awk -F: '{print $2}' ipaddress
181.36.1.8
181.32.1.22
181.32.1.23

1.3 行分隔符

  输出当前处理的行数

$ awk '{print NR}' demo ipaddress

$ awk '{print FNR}' demo ipaddress

2 输出文本 printf

2.1 验证printf命令的%c格式,是把ASCII的Dec列内容转换成Char列内容。(是不是有点像发电报一样)

[root@hp430G2 demo]# cat num

[root@hp430G2 demo]# awk '{printf("%c", $1)}END{printf("\n")}' num
Hello [root@hp430G2 demo]# cat num [root@hp430G2 demo]# awk '{printf("%c%c%c%c%c", $1,$2,$3,$4,$5)}END{printf("\n")}' num
Hello

  因为,printf默认不换行,所有要借助END,而且顺便借助不换行完成单词的拼接。而且,模式数量必须与变量数量(列)对应起来。

2.2 验证printf命令的%s格式

[root@hp430G2 demo]# cat alpha
Hello
[root@hp430G2 demo]# awk '{printf("%s", $1,$2,$3,$4,$5)}END{printf("\n")}' alpha
Hello

2.3 验证printf命令的%d、%i格式

[root@hp430G2 mag37]# cat int
3.1415926
[root@hp430G2 mag37]# awk '{printf("%i", $1)}END{printf("\n")}' int [root@hp430G2 mag37]# awk '{printf("%d", $1)}END{printf("\n")}' int

2.4 验证printf命令的%o指定输出八进制格式。

[root@hp430G2 mag37]# cat oct
181.37.1.42
182.37.4.42
[root@hp430G2 mag37]# awk -F. '{printf("%o.%o.%o.%o\n", $1,$2,$3,$4)}' oct
265.45.1.52
266.45.4.52

2.5 验证printf命令的%X、%x指定输出十六进制格式,分别输出字母部分的大小写。

[root@hp430G2 mag37]# cat hex
181.37.1.42
182.37.4.42
[root@hp430G2 mag37]# awk -F. '{printf("%x.%x.%x.%x\n", $1,$2,$3,$4)}' oct
b5.25.1.2a
b6.25.4.2a
[root@hp430G2 mag37]# awk -F. '{printf("%X.%X.%X.%X\n", $1,$2,$3,$4)}' oct
B5.25.1.2A
B6.25.4.2A

2.6 验证%f,没搞明白,这里输出分割符不能成功指定。

[root@hp430G2 mag37]# cat float
181.37 1.42
182.37 4.42
[root@hp430G2 mag37]# awk '{printf("%F %F\n",$1,$2)}' float
181.370000 1.420000
182.370000 4.420000

  可不可以这样看,在使用了printf时,输出控制的权利就完全交割了,变量被失效了。

3 数学运算

3.1 算术运算

BEGIN{
r=
R=r*
print R
y=R*3.14
print y
}

  支持常见操作符:+ - * / ^ % =,分别表示加、减、乘、除、次方、取余数、赋值。

3.2 条件运算

  支持条件判断:x
< y、x <= y、x > y、x >= y、x == y、x != y、x ~ RE、x !~
RE、&&、||,比较字符串的大小关系、相同关系、匹配正则表达式、多个表达式之间的关系。以及条件表达式:?:

3.3 匹配运算

#!/bin/awk -f

$ ~ /^s/ {print}

  * 注意与上边例子中“print”命令使用“花括号”的位置。

4 模式匹配

4.1 逻辑匹配

输出模式匹配的行;首列大于19、在7到11之间、等于12。

awk '$1>19 {print}' demo.txt
awk '$1==12 {print}' demo.txt

下边的命令,会使得输出值发生变化;为输出结果重新赋值。

awk '$1=12 {print}' demo.txt

4.2 使用正则表达式匹配

使用正则表达式匹配;大写字母后面跟着小写字母、文件大小为2开头、取大小值

awk '/[[:upper:]][[:lower:]]/ {print}' demo.txt
awk '/:..[[:space:]]*2/ {print}' demo.txt
awk '/grep/ {print}' demo.txt

4.3 混合模式匹配

找出以两个数字开头、第4列大于40、并且包含一个大写字母后边跟着一个小写字母的行。

awk '/^[[:digit:]]/ && $4>40 && /[[:lower:]]/ {print}' demo.txt
awk '$1>7 && $1<11 {print}' demo.txt

4.4 区间模式

awk '/^8/,$4==37 {print}' new.txt

4.5 读取数据文件之前的“BEGIN模式”“END”

  由于“begin”块内的命令是在读取文件之前就开始执行的,所以这里的命令不能是操作文件数据的命令。通常可以用来初始化变量。执行顺序就是从“BEGIN”开始,到“模式匹配阶段的数据处理命令”,最后执行“END”。

awk 'BEGIN{print "This is all lines in new.txt."} {print}' new.txt

END模块(这里的“BEGIN”、“END”必须是大写的)

awk '{print} END{print "File is over."}' new.txt

  在该模式下,awk变量的定义、赋值、引用。

[awk@h p]$ cat demo2.txt
This is for test of awk's begin and end.
[awk@h p]$ cat print.awk
#!/bin/awk -f BEGIN{
print "begin"
} {print} END{
print "end\nover"
}
[awk@h p]$ ./print.awk demo2.txt
begin
This is for test of awk's begin and end.
end
over

3 变量

变量
释义
$0
当前正在处理的记录
$n
第n个字段的值
NF
当前处理记录的字段数
NR
当前已经读入的记录数
FILENAME
正在处理的数据文件的名称
FS
字段分割符(默认空格、或制表符)
RS
记录分割符(默认换行)

  NF表示字段数,更有用的可以得到最后一个字段(当每行不同字段时更有用)。可以获取文件名、文件大小

[root@Rsync logs4developers]# tree -fh | grep "M" | awk '{print $NF ,$(NF-1)}'

3.1 普通变量

[awk@h p]$ cat demo1.awk
#!/bin/awk -f BEGIN{
age=
say_hello="hello"
print age
print say_hello
[awk@h p]$ awk -f demo1.awk hello

3.2 内置变量

[awk@h p]$ cat ip_port.txt
172.17.36.40:,
10.134.1.4:,
[awk@h p]$ awk 'BEGIN{FS=":"; RS="\n"; RS=""; ip="ip = "; port=" port = "} {print ip $1 port $2}' ip_port.txt
ip = 172.17.36.40 port = ,
ip = 10.134.1.4 port = ,

4 使用脚本

4.1 在脚本中执行 awk 命令

[web@h p]$ cat my_awk.sh
#!/bin/awk -f {print}
[web@h p]$ ./my_awk.sh demo.txt

4.2 交互模式下的“文件结束符”

运行这个脚本

#!/bin/awk -f

BEGIN{
exitpro="press <ctrl+d> exit the script."
print "test is beginning."
print exitpro
print "============================="
} {print} END{
print "============================="
print "test is over."
}

  脚本运行后,终端等待输入内容,输入结束时需要给脚本文件发送“EOF”信号。按组合键“ctrl+d”退出(Windows平台“ctrl+z”)。

4.3 体会命令执行模式

运行这个脚本

#!/bin/awk -f

{
print
print "Have two print."
}

  当命令“print”没有“file“时,以交互模式执行;执行时这里也是需要“EOF”的,第一条命令执行结束后,执行下一条命令;但是“打印”命令始终是需要一个“EOF”的,而这个信号的接收不会影响后边命令的执行。

  看到上边的例子,我会以为“需要在EOF是因为有个命令的缘故”。去掉脚本中的“print”命令,结果发现依然需要。不同之处在于没有回显。

  在脚本执行时,添加一个“demo.txt”。发现脚本依然可以执行,说明 awk 在执行时,“pattern”、“actions”都可以不需要。

4.4 命令的执行顺序

  awk处理“file”时,按照“记录”依次处理。其中的命令执行是每条命令执行完读入的一条“记录”下一条命令接着处理同样一条“记录”。

[awk@h p]$ cat demo.txt
This is row1.
This is row2.
This is row3.
[awk@h p]$ cat print-file.awk
#!/bin/awk -f {
print
print
}
[awk@h p]$
This is row1.
This is row1.
This is row2.
This is row2.
This is row3.
This is row3.

6 函数

6.1 字符串函数

函数 释义
index(s1,s2) 返回 s2 在 s1 中的位置;返回值从“1”开始,“0”代表不存在
length(s1) 返回字符串的长度;返回整数值
match(s1,RE) 查找匹配正则表达式匹配的字符串;涉及变量“RSTART”,“RLENGTH”
split(s1,array,sep) 以“sep”分割“s1”后,返回“array”
[awk@h p]$ awk 'add=index($0,"sunny") {print add}' demo.txt

[awk@h p]$ awk '{print index($0,"sunny")}' demo.txt

6.2 算术函数

函数 释义
int(x) 返回整数部分
rand() 反馈0~1之间的随机数
srand([x]) 反回一个基于“x”的随机数

7 数组

7.1 数组的定义与引用

#!/bin/awk -f

BEGIN{
port[]=
port[]=
port[]= print port[],port[],port[]
}

7.2 数组遍历

借用“for 循环”遍历数组元素

8 流程控制

9 格式化输出

10 shell交互