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 输出时,需要指定输出格式。
格式 铆定符 |
效果说明 | 例子(页面最下边) |
---|---|---|
%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 "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 {
}
[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交互