正则表达式的扩展,awk、perl等支持正则表达式扩展出来的一些元字符。
扩展的正则表达式元字符及其意义
符号 | 意义 |
---|---|
? | 匹配0个或1个在其之前的那个普通字符 |
+ | 匹配1个或多个在其之前的那个普通字符 |
() | 表示一个字符集合或用在expr中 |
| | 表示“或”,匹配一组可选的字符 |
通过awk可以创建程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其它的功能。awk适合文本处理和报表生成,其语法较为常见,借鉴了某些语言的精华,如c语言等。在linux系统日常处理工作中,发挥着很重要的作用,掌握了awk将会使你的工作量变得高大上。
awk程序由一个主输入循环维持,主输入循环反复执行,直到条件被触发,主输入循环无须由程序员取写,awk已经搭好主输入循环的框架。
任何awk语句都有模式(pattern)和动作(action)组成模式是由一组用于测试输入行是否需要执行动作的规则。动作包含语句,函数和表达式的执行过程,简言之,模式决定动作和时触发和触发时间动作执行对输入行的处理。
[root@localhost awk]# sed '=' test1
1
2
3
4
[root@localhost awk]# awk '/^$/{printf "This is a blank line.\n"}' test1
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
将操作写入文件中
[root@localhost awk]# awk -f test1.awk test1
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
[root@localhost awk]# cat test1.awk
/^$/{printf "This is a blank line.\n"}
直接执行
[root@localhost awk]# ./test1.awk test1
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
[root@localhost awk]# cat test1.awk
#!/usr/bin/awk -f
/^$/{printf "This is a blank line.\n"}
3. 记录和域
awk认为输入文件是结构化的,awk将每个输入文件行定义为记录,行中的每个字符串定义为域,域之间用空格,Tab键或其它符号进行分隔,分隔域的符号就叫做分隔符。
awk定义与操作符来指定执行动作的域,域操作符来指定执行动作的域,域操作符来指定执行动作的域,域操作符后面跟数字或变量来标识域的位置,每条记录的域从1开始编号,如$1表示第一个域,$0表示所有域。
$0表示所有域
[root@localhost awk]# awk '{print $0}' test2
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
$2,$1,$3,$4
[root@localhost awk]# awk '{print $2,$1,$3,$4}' test2
Zhang jy 8497335 shanxi
Zhang jy 8497335 shanxi
Zhang jy 8497335 shanxi
Zhang jy 8497335 shanxi
Zhang jy 8497335 shanxi
[root@localhost awk]# awk 'BEGIN {one=1;two=2} {print $(one+two)}' test2
8497335
8497335
8497335
8497335
8497335
tab键被认为是连续的空格键来处理
[root@localhost awk]# cat test2
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
[root@localhost awk]# awk 'BEGIN {one=1;two=2} {print $(one+two)}' test2
8497335
8497335
8497335
8497335
8497335
8497335
8497335
8497335
用tab键分隔域
[root@localhost awk]# cat test2
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
[root@localhost awk]# awk -F "\t" '{print $1}' test2
jy
jy
jy
jy
jy
[root@localhost awk]# awk -F "\t" '{print $2}' test2
Zhang 8497335 shanxi
[root@localhost awk]# awk -F "\t" '{print $3}' test2 # \t:表示tab
Zhang 8497335 shanxi
Zhang 8497335 shanxi
Zhang 8497335 shanxi
Zhang 8497335 shanxi
注意:不要用多个tab
如果出现多个tab,使用如下命令解决
[root@localhost awk]# cat test2
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
jy Zhang 8497335 shanxi
[root@localhost awk]# awk -F "\t+" '{print $2}' test2
Zhang 8497335 shanxi
Zhang 8497335 shanxi
Zhang 8497335 shanxi
Zhang 8497335 shanxi
Zhang 8497335 shanxi
[root@localhost awk]# awk 'BEGIN {FS=","} {print $1,$3}' test3
jy 8497335 shanxi
jy 8497335 shanxi
jy 8497335 shanxi
jy 8497335 shanxi
jy 8497335 shanxi
4. 关系和布尔运算符
awk定义了一组关系运算符用于awk模式匹配。
awk关系运算符及其意义
元算符 | 意义 |
---|---|
< | 小于 |
> | 大于 |
<= | 小于或等于 |
>= | 大于或等于 |
== | 等于 |
~ | 匹配正则表达式 |
!~ | 不匹配正则表达式 |
$1匹配第一个域为root的内容
[root@localhost awk]# awk 'BEGIN {FS=":"} $1~/root/' passwd
root:x:0:0:root:/root:/bin/bash
所有的域不匹配/root/
[root@localhost awk]# awk 'BEGIN {FS=":"} $0!~/root/' passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
[root@localhost awk]# awk 'BEGIN {FS=":"} {if ($3<$4) print$0}' passwd
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
||表示或 ==是精确匹配
[root@localhost awk]# awk 'BEGIN {FS=":"} {if ($3==1||$4==7) print$0}' passwd
bin:x:1:1:bin:/bin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
5. 表达式
与其它编程一样,awk表达式用于存储,操作和获取数据。一个awk表达式可由数值,字符常量,变量,操作符,函数和正则表达式自由组合而成。
变量是一个值的标识符,定义awk变量非常方便,只需要定义一个变量名并将值赋给它们即可。
变量名只是包含字母,数字和下划线而且不能以数字开通。
定义awk变量无须生命变量类型,每个变量由两种类型的值:字符串值和数值。
awk根据表达式上下文来确定使用哪个值。变量的默认值为0,默认字符串值为空。
统计空白数
[root@localhost awk]# awk '/^$/{print x++}' test1
0
1
2
3
[root@localhost awk]# awk '/^$/{print ++x}' test1
1
2
3
4
平均值的计算
[root@localhost awk]# cat test4
jy,Zhang,8497335,77,88,99,100
jy,Zhang,8497335,25,45,15,65
jy,Zhang,8497335,99,55,26,29
jy,Zhang,8497335,77,19,48,53
jy,Zhang,8497335,93,88,84,72
[root@localhost awk]# cat test4.awk
#!/usr/bin/awk -f
BEGIN {FS=","}
{total=$4+$5+$7
avg=total/4
print $1,avg
}
[root@localhost awk]# chmod o+x test4.awk
[root@localhost awk]# ./test4.awk test4
jy 66.25
jy 33.75
jy 45.75
jy 37.25
jy 63.25
6. 系统变量
awk定义了很多内建变量用于设置环境信息,我们称他为系统变量。
这些系统变量可分为:第一种用于改变awk的默认值,如域分隔符。第二种用于定义系统值,在处理文本时可以读取这些系统值如记录中的域数量,当前记录数,当前文件名等。
NF:为记录的域数量
NR:显示当前的记录数,该值根据读取输入文件的进度而变化,读取第一条记录时,NR=1读取到文件末尾时,NR为该文件包含的记录数。
$0表示打印记录的所有域
FILENAME:保存了当前的输入文件名
[root@localhost awk]# awk 'BEGIN {FS=","} {print NF,NR,$0} END {print FILENAME}' test4
7 1 jy,Zhang,8497335,77,88,99,100
7 2 jy,Zhang,8497335,25,45,15,65
7 3 jy,Zhang,8497335,99,55,26,29
7 4 jy,Zhang,8497335,77,19,48,53
7 5 jy,Zhang,8497335,93,88,84,72
test4
7. 格式输出
前面的例子只涉及awk如何输入文件进行处理,对于输出的格式并未规定。而awk的一大主要功能时产生报表,报表就是要求按照一定的格式输出,awk借鉴c语言的语法,定义了printf输出,它可以规定输出的格式。
[root@localhost awk]# awk 'BEGIN {FS=","} {printf("%s\t%d\n",$2,$7)}' test4
Zhang 100
Zhang 65
Zhang 29
Zhang 53
Zhang 72
[root@localhost awk]# awk 'BEGIN {printf("%c\n",65)}'
A
[root@localhost awk]# awk 'BEGIN {printf("%f\n",35)}'
35.000000
[root@localhost awk]# awk 'BEGIN {printf("%.3f\n",35)}'
35.000
-10s表示将$1控制在10位,并且时左对齐,如果字符串不足15位使用空格补齐
[root@localhost awk]# awk 'BEGIN {FS=","}{printf("%-10s\t%s\n",$1,$3)}' test4
jy 8497335
jy 8497335
jy 8497335
jy 8497335
jy 8497335
8. 内置函数
awk提供了强大的内置字符串函数,用于实现文本的字符串替换 查找以及分割等功能
gsub函数执行字符串替换功能,它将第一个字符串替换位第二个字符串。
index和length函数。indes返回第二个字符串在第一个字符串出现的首位置length返回字符串的长度。
[root@localhost awk]# awk 'BEGIN {FS=":";OFS=":"} gsub(/root/,"student",$1) {print $0}' passwd
student:x:0:0:root:/root:/bin/bash
[root@localhost awk]# awk 'BEGIN {FS=":"} gsub(/root/,"student",$1) {print $0}' passwd
student x 0 0 root /root /bin/bash
[root@localhost awk]# awk 'BEGIN {print index("zjylilhahahxixi","ha")}'
7
[root@localhost awk]# awk 'BEGIN {print length("zjylilhahahxixi")}'
15
练习
输出本机的ip地址
hostname -I
输出本机的根分区使用率
[root@localhost ~]# df -h| awk '/\/dev\/vda1/{print $5}'
68%
[root@localhost ~]# df -h | awk '{if ($6=="/") print$5}'
68%
以passwd文件为例,输出其中以bash结尾的完整记录
[root@localhost awk]# awk '/bash$/{print$0}' passwd
root:x:0:0:root:/root:/bin/bash
student:x:1000:1000:Student User:/home/student:/bin/bash
列出以ro开头的用户记录
[root@localhost awk]# awk '/^ro/{print$0}' passwd
root:x:0:0:root:/root:/bin/bash
输出以a,b,c或着d开头的用户名,宿主目录
[root@localhost awk]# awk 'BEGIN {FS=":"} /^(a|b|c|d)/{print $1,$6}' passwd
bin /bin
daemon /sbin
adm /var/adm
dbus /
avahi /var/run/avahi-daemon
avahi-autoipd /var/lib/avahi-autoipd
chrony /var/lib/chrony
colord /var/lib/colord
abrt /etc/abrt
apache /usr/share/httpd
dhcpd /
输出其中用名以a开头,登陆shell以nologin结尾的用户名,登陆shell
[root@localhost awk]# awk '/^a/&&/nologin$/' passwd
adm:x:3:4:adm:/var/adm:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
输出第三行的用户记录
[root@localhost awk]# awk '{if (NR==3) print$0}' passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
输出奇数(行号NR除以2余数为1)行的用户记录
[root@localhost awk]# awk '{if (NR%2!=0) print$0}' passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
ovirtagent:x:175:175:RHEV-M Guest Agent:/usr/share/ovirt-guest-agent:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
student:x:1000:1000:Student User:/home/student:/bin/bash
colord:x:997:995:User for colord:/var/lib/colord:/sbin/nologin
libstoragemgmt:x:996:994:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
qemu:x:107:107:qemu user:/:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
radvd:x:75:75:radvd user:/:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
dhcpd:x:177:177:DHCP server:/:/sbin/nologin
输出偶数(行号除以2余数为0)行的用户记录
[root@localhost awk]# awk '{if (NR%2==0) print$0}' passwd
bin:x:1:1:bin:/bin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
halt:x:7:0:halt:/sbin:/sbin/halt
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
unbound:x:995:993:Unbound DNS resolver:/etc/unbound:/sbin/nologin
saslauth:x:994:76:"Saslauthd user":/run/saslauthd:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
gnome-initial-setup:x:993:991::/run/gnome-initial-setup/:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin