目录
一、Awk 实战讲解
1.1 awk 的原理
1.2 BEGIN 和 END 模块
1.3 运算符
1.4 常用 awk 内置变量
1.5 awk 正则
1.6 awk 常用字符串函数
一、Awk 实战讲解
awk 是一种很棒的语言,它适合文本处理和报表生成,其语法较为常见,借鉴了某些语言的一些精华,如 C 语言等。在 linux 系统日常处理工作中,发挥很重要的作用,掌握了 awk 将会使你的工作变的高大上。 awk 是三剑客的老大,利剑出鞘,必会不同凡响。
1.1 awk 的原理
通过一个简短的命令,我们来了解其工作原理:
$ awk '{print $0}' /etc/passwd
$ echo hhh | awk '{print "hello,world"}'
$ awk '{ print "hiya" }' /etc/passwd
你将会见到 /etc/passwd 文件的内容出现在眼前。现在,解释 awk 做了些什么。调用 awk时,我们指定 /etc/passwd 作为输入文件。执行 awk 时,它依次对 /etc/passwd 中的每一行执行 print 命令。所有输出都发送到 stdout,所得到的结果与执行 cat /etc/passwd 完全相同。
现在,解释 { print } 代码块。在 awk 中,花括号用于将几块代码组合到一起,这一点类似于 C 语言。在代码块中只有一条 print 命令。在 awk 中,如果只出现 print 命令,那么将打印当前行的全部内容。
再次说明,awk 对输入文件中的每一行都执行这个脚本。
$ awk -F":" '{ print $1 }' /etc/passwd
$ awk -F":" '{ print $1 $3 }' /etc/passwd
$ awk -F":" '{ print $1 " " $3 }' /etc/passwd
$ awk -F":" '{ print "username: " $1 "\t\tuid:" $3" }' /etc/passwd
1.2 BEGIN 和 END 模块
通常,对于每个输入行,awk 都会执行每个脚本代码块一次。然而,在许多编程情况中,
可能需要在 awk 开始处理输入文件中的文本之前执行初始化代码。对于这种情况,awk 允许
您定义一个 BEGIN 块。我们在前一个示例中使用了 BEGIN 块。因为 awk 在开始处理输入文
件之前会执行 BEGIN 块,因此它是初始化 FS(字段分隔符)变量、打印页眉或初始化其它
在程序中以后会引用的全局变量的极佳位置。
awk 还提供了另一个特殊块,叫作 END 块。awk 在处理了输入文件中的所有行之后执行
这个块。通常,END 块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。
1.3 运算符
- awk 赋值运算符
a+5;等价于: a=a+5; 其他同类
[root@master1-admin ~]# awk 'BEGIN{a=5;a+=5;print a}'
10
- awk 逻辑运算符
[root@master1-admin ~]# awk 'BEGIN{a=1;b=2;print(a>2&&b>1,a=1||b>1)}'
0 1
- awk 正则运算符
[root@master1-admin ~]# awk 'BEGIN{a="100testaaa";if(a~/100/){print "ok"}}'
ok
[root@master1-admin ~]# echo | awk 'BEGIN{a="100testaaa"}a~/100/{print "ok"}'
ok
- 关系运算符
如:> < 可以作为字符串比较,也可以用作数值比较,关键看操作数如果是字符串就会转换为字符串比较。两个都为数字才转为数值比较。字符串比较:按照 ascii 码顺序比较。
[root@master1-admin ~]# awk 'BEGIN{a="11";if(a>=9){print "ok"}}'
[root@master1-admin ~]# awk 'BEGIN{a=11;if(a>=9){print "ok"}}'
ok
[root@master1-admin ~]# awk 'BEGIN{a;if(a>=b){print "ok"}}'
ok
- awk 算术运算符
说明,所有用作算术运算符进行操作,操作数自动转为数值,所有非数值都变为 0。
[root@master1-admin ~]# awk 'BEGIN{a="b";print a++,++a}'
0 2
[root@master1-admin ~]# awk 'BEGIN{a="20b4";print a++,++a}'
20 22
1.4 常用 awk 内置变量
- 字段分隔符 FS
FS="\t" 一个或多个 Tab 分隔
[root@master1-admin ~]# vim tab.txt
ww CC IDD
[root@master1-admin ~]# awk 'BEGIN{FS="\t+"}{print $1,$2,$3}' tab.txt
ww CC IDD
FS="[[:space:]+]" 一个或多个空白空格,默认的
[root@master1-admin ~]# vim space.txt
we are studing awk now!
[root@master1-admin ~]# awk -F [[:space:]+] '{print $1,$2,$3,$4,$5}' space.txt
we are
[root@master1-admin ~]# awk -F [[:space:]+] '{print $1,$2}' space.txt
we are
FS="[" ":]+" 以一个或多个空格或:分隔
[root@master1-admin ~]# vim hello.txt
root:x:0:0:root: /root:/bin/bash
[root@master1-admin ~]# awk -F [" ":]+ '{print $1,$2,$3}' hello.txt
root x 0
-
字段数量 NF
[root@master1-admin ~]# vim hello.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin:888
[root@master1-admin ~]# awk -F ":" 'NF==8{print $0}' hello.txt
bin:x:1:1:bin:/bin:/sbin/nologin:888
- 记录数量 NR
[root@master1-admin ~]# ifconfig ens32
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.78.135 netmask 255.255.255.0 broadcast 192.168.78.255
inet6 fe80::20c:29ff:fe2e:bef7 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:2e:be:f7 txqueuelen 1000 (Ethernet)
RX packets 3553 bytes 295498 (288.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 13802 bytes 1002340 (978.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@master1-admin ~]# ifconfig ens32 | awk -F [" ":]+ 'NR==2{print $3}'
192.168.78.135
- RS 记录分隔符变量
将 FS 设置成 "\n" 告诉 awk 每个字段都占据一行。通过将 RS 设置成 "",还会告诉 awk
每个地址记录都由空白行分隔。
[root@master1-admin ~]# vim recode.txt
Jimmy the Weasel
100 Pleasant Drive
San Francisco, CA 12345
Big Tony
200 Incognito Ave.
Suburbia, WA 67890
[root@master1-admin ~]# vim awk.txt
#!/bin/awk
BEGIN {
FS="\n"
RS=""
}
{
print $1 ", " $2 ", " $3
}
[root@master1-admin ~]# awk -f awk.txt recode.txt
Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345
Big Tony, 200 Incognito Ave., Suburbia, WA 67890
-
OFS 输出字段分隔符
[root@master1-admin ~]# awk 'BEGIN{FS=":"}{print $1","$2","$3}' hello.txt
root,x,0
bin,x,1
[root@master1-admin ~]# awk 'BEGIN{FS=":";OFS="#"}{print $1,$2,$3}' hello.txt
root#x#0
bin#x#1
-
ORS 输出记录分隔符
[root@master1-admin ~]# vim awk.txt
#!/bin/awk
BEGIN {
FS="\n"
RS=""
ORS="\n\n"
}
{
print $1 ", " $2 ", " $3
}
[root@master1-admin ~]# awk -f awk.txt recode.txt
Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345
Big Tony, 200 Incognito Ave., Suburbia, WA 67890
1.5 awk 正则
- 规则表达式
awk '/REG/{action} ' file,/REG/ 为正则表达式,可以将 $0 中,满足条件的记录送入到:
action 进行处理
[root@master1-admin ~]# awk '/root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@master1-admin ~]# awk -F : '$5~/root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
# 取出 ip
[root@master1-admin ~]# ifconfig ens32 | awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print $3}'
192.168.78.135
- 布尔表达式
awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时,awk 才执行代码块。
[root@master1-admin ~]# awk -F: '$1=="root"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@master1-admin ~]# awk -F: '($1=="root")&&($5=="root"){print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
1.6 awk 常用字符串函数
- 替换
在 info 中查找满足正则表达式,/[0-9]+/ 用 ”!” 替换,并且替换后的值,赋值给 info 未给 info 值,默认是 $0
[root@master1-admin ~]# awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'
this is a test!test!
- 查找
# 未找到,返回 0
[root@master1-admin ~]# awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'
ok
-
匹配查找
如果查找到数字则匹配成功返回 ok,否则失败,返回未找到
[root@master1-admin ~]# awk 'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}'
ok
- 截取
# 从第 4 个 字符开始,截取 10 个长度字符串
[root@master1-admin ~]# awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}'
s is a tes
- 分割
# 分割 info,动态创建数组 tA,awk for ...in 循环,是一个无序的循环。并不是从数组下标 1...n 开始
[root@master1-admin ~]# awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}'
4
4 test
1 this
2 is
3 a