文本三剑客——awk
1、awk 基础介绍与使⽤
awk:Aho, Weinberger, Kernighan,报告⽣成器,格式化⽂本输出,GNU/Linux发布的AWK⽬前由⾃由软件基⾦会(FSF)进⾏开发和维护,通常也称它为 GNU AWK。
有多种版本:
AWK:原先来源于 AT & T 实验室的的AWK
NAWK:New awk,AT & T 实验室的AWK的升级版
GAWK:即GNU AWK。所有的GNU/Linux发布版都⾃带GAWK,它与AWK和NAWK完全兼
容
GNU AWK ⽤户⼿册⽂档:
https://www.gnu.org/software/gawk/manual/gawk.html
gawk:模式扫描和处理语⾔,可以实现下⾯功能
文本处理
输出格式化的文本报表
执行算数运算
执行字符串操作
语法格式
[root@centos7 ~]#ll `which awk`
lrwxrwxrwx. 1 root root 4 10⽉ 18 2021 /usr/bin/awk -> gawk
[root@centos7 ~]#rpm -qi gawk
Name : gawk
Version : 4.0.2
Release : 4.el7_3.1
Architecture: x86_64
Install Date: 2021年10⽉18⽇ 星期⼀ 21时16分05秒
Group : Applications/Text
Size : 2435978
License : GPLv3+ and GPL and LGPLv3+ and LGPL and BSD
Signature : RSA/SHA256, 2017年06⽉29⽇ 星期四 20时40分38秒, Key ID 24c6a8a7f4a8
0eb5
Source RPM : gawk-4.0.2-4.el7_3.1.src.rpm
Build Date : 2017年06⽉29⽇ 星期四 05时52分50秒
Build Host : c1bm.rdu2.centos.org
Relocations : (not relocatable)
Packager : CentOS BuildSystem <http://bugs.centos.org>
Vendor : CentOS
URL : http://www.gnu.org/software/gawk/gawk.html
Summary : The GNU version of the awk text processing utility
Description :
The gawk package contains the GNU version of awk, a text processing
utility. Awk interprets a special-purpose programming language to do
quick and easy text pattern matching and reformatting jobs.
Install the gawk package if you need a text processing utility. Gawk is
considered to be a standard Linux tool for processing text.1.1 awk语法说明
语法格式
awk [options] 'program' file(s)
awk [options] -f programfile var=value file(s)常⽤命令选项
-F fs fs指定输⼊分隔符,默认分隔符是匹配连续的空⽩符,⽀持正则匹配进⾏分割,如-F:
-v var=value 赋值⼀个⽤户定义变量,将外部变量传递给awk
-f scripfile 从脚本⽂件中读取awk命令
-m[fr] val 对val值设置内在限制,-mf选项限制分配给val的最⼤块数⽬;-mr选项限制记录的
最⼤数⽬。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适⽤。
awk通过指定处理模式 program 对数据进⾏处理;通常情况下处理模式 program 放在单引号
中, program 格式如下:
pattern{action string}
pattern模式:决定了何时触发处理数据的动作
BEGIN模式:⽤于awk处理数据之前做对应操作,⽐如:打印标题,变量初始化
正则匹配模式:awk默认模式,⽤于匹配对的数据进⾏处理;不指定匹配条件的话,则处理全
部数据⾏。
END模式:⽤于awk处理数据后做对应操作,⽐如:统计总和
action :定义处理数据的动作(操作),处理操作要写到⼤括号中。
1.2 awk⼯作原理
第⼀步:执⾏BEGIN模式对应的操作
第⼆步:从⽂件或标准输⼊(stdin)读取⼀⾏数据,满⾜匹配条件进⾏处理,不符合条件的继续
读取下⼀⾏数据,直到数据全部读取完毕。
第三步:全部数据处理完毕之后,执⾏END模式对应的操作
1.3 处理动作 print
处理动作 print 语法
<模式>{print item1,item2.....}
说明
如果不指定模式,默认为匹配模式,且匹配整⾏数据
item输出信息可以是字符串,数字,也可以是分割的字段,变量,awk表达式
如果指定输出信息是固定字符串,建议使⽤双引号引起来!
按照分割符,第⼀列为 $1 ,第⼆列为 $2 ......依次类推, $0 表示输出整⾏数据
如果不知道item输出信息,默认输出匹配到的整⾏数据
示例:把 seq 10 ⽣成的10条数据替换为固定字符串 hello gawk
[root@centos7 ~]#seq 10 | awk '{print "hello gawk"}'
[root@centos7 ~]#seq 2 | awk '{print 2*3}'
6
6
[root@centos7 ~]#seq 2 | awk '{print "2*3"}'
2*3
2*3示例:指定awk分割符为冒号:,把 /etc/passwd ⽂件中整⾏输数据替换为 hello gawk
[root@centos7 ~]#awk -F: '{print "hello gawk"}' /etc/passwd
[root@centos7 ~]#awk -F: '{print "zhou"}' /etc/passwd示例:指定awk分割符为冒号:打印 /etc/passwd ⽂件中整⾏数据
[root@centos7 ~]#awk -F: '{print}' /etc/issue
\S
Kernel \r on an \m
[root@centos7 ~]#awk -F: '{print $0}' /etc/issue
\S
Kernel \r on an \m
[root@centos7 ~]#awk -F: '' /etc/issue示例:打印 /etc/passwd 以指定awk分割符为冒号:,第⼀列和第三列信息
[root@centos7 ~]#awk -F: '{print $1}' /etc/passwd
[root@centos7 ~]#awk -F: '{print $1$3}' /etc/passwd说明:awk默认打印多个列之间紧挨着,要想把多个列之间分割,如下⽅法
多个列之间加⼊固定字符作为分割
多个列之间加⼊⼀个逗号,在awk的动作中逗号表示空格
示例:取磁盘空间利⽤率
#默认是空⽩符是分隔符
[root@centos7 ~]#df | awk '{print $1,$5}'
⽂件系统 已⽤%
/dev/sda5 5%
devtmpfs 0%
tmpfs 0%
tmpfs 1%
tmpfs 0%
/dev/sda2 26%
tmpfs 0%
/dev/sr0 100%按照上⾯的⽅法,可以取出利⽤率,但是利⽤路后⾯带有%符号,如何把百分号去掉?
[root@centos7 ~]#df | awk '{print $1,$5}' | tr -d %
⽂件系统 已⽤
/dev/sda5 5
devtmpfs 0
tmpfs 0
tmpfs 1
tmpfs 0
/dev/sda2 26
tmpfs 0
/dev/sr0 100
#使⽤扩展的正则表达式
[root@centos7 ~]#df | awk -F ' +|%' '{print $1,$5}'
⽂件系统 已⽤
/dev/sda5 5
devtmpfs 0
tmpfs 0
tmpfs 1
tmpfs 0
/dev/sda2 26
tmpfs 0
/dev/sr0 100
[root@centos7 ~]#df|awk -F'[[:space:]]+|%' '{print $1,$5}'
⽂件系统 已⽤
/dev/sda5 5
devtmpfs 0
tmpfs 0
tmpfs 1
tmpfs 0
/dev/sda2 26
tmpfs 0
/dev/sr0 100只取出真正磁盘的利⽤率,⽽虚拟磁盘利⽤率则舍去
[root@centos7 ~]#df | awk -F' +|%' '{print $1,$5}' | grep '^/dev'
/dev/sda5 5
/dev/sda2 26
/dev/sr0 100
[root@centos7 ~]#df | awk -F' +|%' '/^\/dev/{print $1,$5}'
/dev/sda5 5
/dev/sda2 26
/dev/sr0 100
[root@centos7 ~]#df | grep "^/dev/sd" | awk -F"[[:space:]]+|%" '{print $5}'
5
26
⾯试题:取出⽹站访问量最⼤的前3个IP
[root@centos7 ~]#awk '{print $1}' access_log | sort | uniq -c | sort -nr | hea
d -3
4870 172.20.116.228
3429 172.20.116.208
2834 172.20.0.222⾯试题:取 ifconfig 输出结果中的IP地址
[root@centos7 ~]#ifconfig ens33 | awk '/netmask/'
inet 192.168.2.71 netmask 255.255.255.0 broadcast 192.168.2.255
[root@centos7 ~]#ifconfig ens33 | awk '/netmask/{print $2}'
192.168.2.71
[root@centos7 ~]# hostname -I
192.168.2.71
[root@centos7 ~]#ifconfig ens33 | sed -n '2p' | awk '{print $2}'
192.168.2.71
#CentOS6 取IP
[root@centos7 ~]#ifconfig ens33 |awk -F " +|:" '/Mask/{print $4}'
192.168.2.71
[root@centos7 ~]#ifconfig ens33 | sed -rn '2s/^[^0-9]+([0-9.]+) .*$/\1/p'
192.168.2.71⾯试题:⽂件host_list.log 如下格式,请提取”.ops.com”前⾯的主机名部分并写⼊到回到该⽂件中
[root@centos7 ~]#vim host_list.log
1 www.ops.com
2 blog.ops.com
3 study.ops.com
4 linux.ops.com
5 python.ops.com
[root@centos7 ~]#awk -F'[ .]' '{print $2}' host_list.log
www
blog
study
linux
python
[root@centos7 ~]#awk -F"[ .]" '{print $2}' host_list.log
www
blog
study
linux
python
[root@centos7 ~]#awk -F'[ .]' '{print $2}' host_list.log >> host_list.log
[root@centos7 ~]#cat host_list.log
1 www.ops.com
2 blog.ops.com
3 study.ops.com
4 linux.ops.com
5 python.ops.com
www
blog
study
linux
python1.4 处理动作 printf
printf处理动作:实现格式化输出信息
awk '{printf "FORMAT",expr-list}'awk 'BEGIN{}PAttern{action}END{}'
说明
FORMAT:指定格式化的格式,必须指定格式化格式
expr-list:指定输出的信息列表,列表每个信息对应格式符
printf:默认不⾃动换⾏,需要格式化输出后⾯加上换⾏符 \n
FORMAT格式化输出有两部分组成:格式符 + 修饰符
修饰符
#[.#] 第⼀个数字控制显示的宽度(默认右对⻬);
第⼆个#对于⼩数表示⼩数点后精度, 如:%3.1f; 对于整数表示整数位数,不⾜则前⾯补0,如:%.3d
- 左对⻬宽度, 如:%-15s
+ 显示数值的正负符号 如:%+d示例:
[root@centos7 ~]#awk -F: '{printf "%s",$1}' /etc/passwd
[root@centos7 ~]#awk -F: '{printf "%s\n",$1}' /etc/passwd
[root@centos7 ~]#awk -F: '{printf "%20s\n",$1}' /etc/passwd
[root@centos7 ~]#awk -F: '{printf "%-20s\n",$1}' /etc/passwd
[root@centos7 ~]#awk -F: '{printf "%-20s | %d10\n",$1,$3}' /etc/passwd
[root@centos7 ~]#awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
[root@centos7 ~]#awk -F: '{printf "%20s %-10d\n",$1,$3}' /etc/passwd
[root@centos7 ~]#awk -F: '{printf "username:%-20s userid:%d\n",$1,$3}' /etc/pa
sswd
[root@centos7 ~]#awk -F: '{printf "username:%-20s userid:%.3f\n",$1,$3}' /etc/
passwd
[root@centos7 ~]#awk -F: '{printf "username:%-20s userid:%.3d\n",$1,$3}' /etc/
passwd2、awk变量
awk命令中的变量分为:awk内置变量和⾃定义变量,内置变量如下
2.1 内置变量
FS:输⼊字段分隔符,默认为空⽩字符,功能相当于 -F
#定义FS变量值作为awk分隔符
[root@centos7 ~]#awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
#处理数据动作调⽤awk变量,awk调⽤内置变量不需要加$符号
[root@centos7 ~]#awk -v FS=":" '{print $1FS$3}' /etc/passwd
[root@centos7 ~]#awk -F: '{print $1FS$3}' /etc/passwd
#awk调⽤shell中变量
[root@centos7 ~]#S=:;awk -v FS=$S '{print $1FS$3}' /etc/passwd
#-F 和 FS变量功能⼀样,同时使⽤会冲突,则后⾯定义⽣效
[root@centos7 ~]#awk -v FS=":" -F";" '{print $1FS$3}' /etc/passwd |head -n3
root:x:0:0:root:/root:/bin/bash;
bin:x:1:1:bin:/bin:/sbin/nologin;
daemon:x:2:2:daemon:/sbin:/sbin/nologin;
[root@centos7 ~]#awk -F";" -v FS=":" '{print $1FS$3}' /etc/passwd |head -n3
root:0
bin:1
daemon:2
OFS:输出字段分隔符,默认为空⽩字符
[root@centos7 ~]#awk -F: -v OFS='---' '{print $1,$7}' /etc/passwd |head -n3
root---/bin/bash
bin---/sbin/nologin
daemon---/sbin/nologin RS:输⼊记录record分隔符,指定输⼊时的换⾏符
ORS:输出记录分隔符,输出时⽤指定符号代替换⾏符
#看如下⽂件内容
[root@centos7 ~ ]# cat test.txt
AA,BB;CC,DD
EE,FF;GG,HH
#awk默认以换⾏符作为⼀条记录进⾏处理
[root@centos7 ~ ]# awk -v FS=',' -v OFS=' --- ' '{print $1,$3}' test.txt
AA --- DD
EE --- HH
#当设置RS为; 表示以分号作为awk处理记录的分隔符, 也就是: AA,BB 是处理⼀条记录, CC,DD\nEE,
FF 是另⼀条记录, GG,HH ⼀条记录
[root@centos7 ~]#awk -v FS=',' -v OFS=' --- ' -v RS=';' '{print $1,$2}' test.t
xt
AA --- BB
CC --- DD
EE
GG --- HH
[root@centos7 ~]#awk -v FS=',' -v OFS=' --- ' -v RS=';' -v ORS='+++' '{print
$1,$2}' test.txt
AA --- BB+++CC --- DD
EE+++GG --- HH
+++NF: 字段数量
[root@centos7 ~]#awk -v FS=',' -v OFS=' --- ' -v RS=';' '{print NF}' test.txt
2
3
2
#通过 NF 变量取/etc/passwd⽂件的倒数第⼆列数据
awk -v FS=: '{print NF}' /etc/passwd
[root@centos7 ~]#awk -v FS=: '{print $(NF-1)}' /etc/passwd | head -2
/root
/bin
[root@centos7 ~]#awk -F: '{print $NF}' /etc/passwd
[root@centos7 ~]#awk -F: '{print $1,$NF}' /etc/passwd
[root@centos7 ~]#ls /mnt/Packages/ | awk -F'.' '{print $(NF-1)}' | sort | uni
q -c | sort -nr
2665 x86_64
1405 noarch
1 TRANS⾯试题:统计当前访问服务器IP的前三名访问次数
[root@centos7 ~]#ss -nt | grep '^ESTAB'|tr -s ' ' | cut -d' ' -f5 | cut -d':'
-f1 | sort | uniq -c | sort -nr | head -n3
1 192.168.2.2
[root@centos7 ~]#cat ss2.log | awk -F" +|:" '{print $6}' | sort | uniq -c | so
rt -nr
[root@centos7 ~]#ss -nt|awk -F' +|:' '/ESTAB/{print $(NF-2)}'|sort|uniq -c
1 192.168.2.2范例:每⼗分钟检查将连接数超过100个以上的IP放⼊⿊名单拒绝访问
#⽅法⼀
#!/bin/bash
LINK=100
while true;do
ss -nt | awk -F"[[:space:]]+|:" '/^ESTAB/{print $(NF-2)}'|sort |uniq -c| whil
e read count ip;do
if [ $count -gt $LINK ];then
iptables -A INPUT -s $ip -j REJECT
fi
done
done
[root@centos8 ~]#chmod +x /root/deny_dos.sh
[root@centos8 ~]#crontab -e
[root@centos8 ~]#crontab -l
*/10 * * * * /root/deny_dos.sh
#⽅法⼆
#!/bin/bash
IPLIST=`cat ss2.log | awk -F" +|:" '{print $6}' | sort | uniq -c | sort -nr |
awk '{print $2}' | head -3`
for ip in $IPLIST ; do
iptables -A INPUT -s $ip -j REJECT
done
[root@centos7 ~]#iptables -vnL
[root@centos7 ~]#bash dos.sh
[root@centos7 ~]#iptables -vnL
Chain INPUT (policy ACCEPT 6 packets, 364 bytes)
pkts bytes target prot opt in out source destinatio
n
0 0 REJECT all -- * * 223.88.255.148 0.0.0.0/0
reject-with icmp-port-unreachable
0 0 REJECT all -- * * 119.250.197.118 0.0.0.0/0
reject-with icmp-port-unreachable
0 0 REJECT all -- * * 183.202.63.36 0.0.0.0/0
reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destinatio
n
Chain OUTPUT (policy ACCEPT 4 packets, 392 bytes)
pkts bytes target prot opt in out source destination
[root@centos7 ~]#iptables -FNR:记录的编号
[root@centos7 ~]#cat test.txt
AA,BB;CC,DD
EE,FF;GG,HH
[root@centos7 ~]#awk -v RS=';' '{print NR,$0}' test.txt
[root@centos7 ~]#awk -v RS=';' '{print NR,$0}' test.txt
1 AA,BB
2 CC,DD
EE,FF
3 GG,HH
[root@centos7 ~]#seq 5 | awk '{print NR}'
1
2
3
4
5
[root@centos7 ~]#awk '{print NR}' /etc/issue
1
2
3
[root@centos7 ~]#awk '{print NR,$0}' /etc/issue /etc/centos-release
1 \S
2 Kernel \r on an \m
3
4 CentOS Linux release 7.4.1708 (Core)
# 取/etc/passwd⽂件的第⼆⾏信息
# NR利⽤ == 指定对应⾏号
[root@centos7 ~ ]# awk 'NR==2' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin⾯试题:取出ifconfig显示结果的IP地址
[root@centos7 ~]#ifconfig ens33 | awk '/netmask/{print $2}'
192.168.2.71
[root@centos7 ~]#ifconfig ens33 | awk 'NR==2{print $2}'
192.168.2.71FNR: 各⽂件分别计数,记录的编号
[root@centos7 ~]#awk '{print NR,$0}' /etc/issue /etc/hosts
1 \S
2 Kernel \r on an \m
3
4 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomai
n4
5 ::1 localhost localhost.localdomain localhost6 localhost6.localdomai
n6
[root@centos7 ~]#awk '{print FNR,$0}' /etc/issue /etc/hosts
1 \S
2 Kernel \r on an \m
3
1 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomai
n4
2 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6FILENAME:显示当前记录所在⽂件名
[root@centos7 ~]#awk '{print FNR,FILENAME,$0}' /etc/issue /etc/hosts
1 /etc/issue \S
2 /etc/issue Kernel \r on an \m
3 /etc/issue
1 /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost
4.localdomain4
2 /etc/hosts ::1 localhost localhost.localdomain localhost6 6.localdomain6ARGC:命令⾏参数的个数
[root@centos7 ~]#awk '{print ARGC}' /etc/issue /etc/redhat-release
3
3
3ARGV:数组,保存的是命令⾏所给定的各参数,每⼀个参数:ARGV[0],......
[root@centos7 ~ ]# awk 'END{print ARGC,ARGV[0],ARGV[1],ARGV[2]}' /etc/passwd /
etc/issue
3 awk /etc/passwd /etc/issue
[root@centos7 ~]#awk 'BEGIN{print ARGV[0]}' /etc/issue /etc/redhat-release
awk
[root@centos7 ~]#awk 'BEGIN{print ARGV[1]}' /etc/issue /etc/redhat-release
/etc/issue
[root@centos7 ~]#awk 'BEGIN{print ARGV[2]}' /etc/issue /etc/redhat-release
/etc/redhat-release
[root@centos7 ~]#awk 'BEGIN{print ARGV[3]}' /etc/issue /etc/redhat-release2.2 ⾃定义变量
awk命令中支持自定义变量awk -v 用于自定义awk变量,格式为:awk -v var=value 在program的处理动作action中直接定义,注意点:多个处理动作以分号隔开
[root@centos7 ~]#awk -v test='hello world' 'BEGIN{print test}'
hello world
[root@centos7 ~]#awk -v test='hello world' '{print test}' /etc/issue
hello world
hello world
hello world
[root@centos7 ~]#awk '{test="hello world";print test}' /etc/issue
hello world
hello world
hello world注意:awk中不使用参数 -v 声明变量时,在BEGIN过程中不可用。直到首行输入完成以后,变量才可用。可以通过-v 参数,让awk在执行 BEGIN之前得到变量的值 。命令行中每一个指定的变量都需要一个-v参数
[root@centos7 ~ ]# awk a=10 'BEGIN{print a}'
awk: fatal: cannot open file `BEGIN{print a}' for reading (No such file or directory)
[root@centos7 ~ ]# awk -v a=10 'BEGIN{print a}'
10
[root@rocky8 ~]# awk -F: '{sex="male";print $1,sex,age;age=18}' /etc/passwd
root male
bin male 18
daemon male 18
adm male 18
lp male 18
sync male 18
shutdown male 18
halt male 18
mail male 18
operator male 18
games male 18
ftp male 18
nobody male 18
dbus male 18
systemd-coredump male 18
systemd-resolve male 18
tss male 18
polkitd male 18
unbound male 18
sssd male 18
chrony male 18
sshd male 18示例
[root@centos7 ~]#cat test.awk
{print script,$1,$2}
[root@centos7 ~]#awk -F: -f test.awk script="awk" /etc/passwd示例
#说明:age赋值处于处理操作print后面,会赋值给下次处理操作变量age
[root@centos7 ~ ]# awk -F: '{sex="male";print $1,sex,age;age=age+1}' /etc/passwd
root male
bin male 1
daemon male 2
adm male 33、awk运算与判断
3.1 算数运算
注意:所有用作算术运算符进行操作,操作数自动转为数值,所有非数值都变为0
[root@centos7 ~ ]# awk 'BEGIN{a="a";print a++,++a}'
0 2注意:将正数转换为负数
[root@centos7 ~]# awk 'BEGIN{n=1;print -n,-++n}'
-1 -23.2 赋值运算
示例:
[root@centos7 ~]#seq 10 | awk 'n++'
2
3
4
5
6
7
8
9
10
[root@centos7 ~]#seq 10 | awk '++n'
1
2
3
4
5
6
7
8
9
10
[root@centos7 ~]#awk 'BEGIN{i=0;print ++i,i}'
1 1
[root@centos7 ~]#awk 'BEGIN{i=0;print i++,i}'
0 1
[root@centos7 ~]#awk 'BEGIN{n=0;print n++}'
0
[root@centos7 ~]#awk -v n=0 '!n++' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@centos7 ~]#awk -v n=0 '!n++{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@centos7 ~]#awk -v n=0 '!n++{print n}' /etc/passwd
1
[root@centos7 ~]#awk -v n=1 '!n++{print n}' /etc/passwd
[root@centos7 ~]#awk -v n=0 '!++n{print n}' /etc/passwd
[root@centos7 ~]#awk -v n=0 '!++n' /etc/passwd
[root@centos7 ~]#awk -v n=-1 '!++n' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@centos7 ~]#awk 'BEGIN{print i}'
[root@centos7 ~]#awk 'BEGIN{print !i}'
1
[root@centos7 ~]#awk -v i=1 'BEGIN{print !i}'
0
[root@centos7 ~]#awk -v i=-1 'BEGIN{print !i}'
0
[root@centos7 ~]#awk -v i=0 'BEGIN{print !i}'
1
[root@centos7 ~]#awk -v i=aaa 'BEGIN{print !i}'
0
[root@centos7 ~]#awk -v i='' 'BEGIN{print !i}'
13.3 比较运算
示例:只查看/etc/passwd文件的第二行数据
[root@centos7 ~]#awk 'NR==2' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
[root@centos7 ~]#awk 'NR!=1' /etc/passwd示例:取偶数行和奇数行
[root@centos7 ~]#seq 10 | awk 'NR%2==0'
2
4
6
8
10
[root@centos7 ~]#seq 10 | awk 'NR%2==1'
1
3
5
7
9
[root@centos7 ~]#seq 10 | awk 'NR%2!=0'
1
3
5
7
9
[root@centos7 ~]#seq 10 | awk 'NR%2!=1'
2
4
6
8
10
第一步:i是空
第二步:!i=1
第三步:i=!i,i=1
第四步:判断i是真,所以print $0
[root@centos7 ~]#seq 10 | awk 'i=!i'
1
3
5
7
9
[root@centos7 ~]#seq 10 | awk '!(i=!i)'
2
4
6
8
10
[root@centos7 ~]#seq 5 | awk '{i=!i;print i}'
1
0
1
0
1示例:查看/etc/passwd文件中uid大于1000的数据行
[root@centos7 ~]#awk -F: '$3>=1000' /etc/passwd
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin示例:打印文件奇数行数据和偶数行
#奇数行
awk 'NR%2==0' /etc/passwd
awk 'NR%2!=1' /etc/passwd
#偶数行
awk 'NR%2==1' /etc/passwd
awk 'NR%2!=0' /etc/passwd3.4 逻辑运算
示例
awk -F: '$3>=0 && $3<=1000 {print $1,$3}' /etc/passwd
[root@centos7 ~]#awk -F: '$3==0 || $3>=1000 {print $1,$3}' /etc/passwd
root 0
nfsnobody 65534
[root@centos7 ~]#awk -F: '$3==0 && $3<=10 {print $1,$3}' passwd
root 0取反操作
awk -v n=0 'BEGIN{print !n}'
awk -v n=5 'BEGIN{print !n}'
awk -v n=-2 'BEGIN{print !n}'
awk -v n='abc' 'BEGIN{print !n}'
awk -v n=' ' 'BEGIN{print !n}'
awk -v n='' 'BEGIN{print !n}'
awk -v n=0 '!n++' /etc/passwd
----------------------------------------------------------------------------
说明:上面命令相当于 awk -v n=0 '!n++{print $0}' /etc/passwd
awk -v定义了n变量,初始化为0, 处理/etc/passwd文件数据
处理第一条记录:计算!n > !0 > 1 结果为真,则输出一条记录;最后 n++ ==> n=1
处理第二条记录: 计算!n > !1 > 0 结果为假,则不输出记录数据;最后 n++ ==> n=2
----------------------------------------------------------------------------
awk -v n=0 '!++n{print $0}' /etc/passwd
----------------------------------------------------------------------------
awk -v定义了n变量,初始化为0, 处理/etc/passwd文件数据
处理第一条记录:计算++n ==> n=1 然后计算 !n > !1 > 0 结果为假,则不输出任何信息
处理第二条记录: 计算++n ==> n=2 然后计算 !n > !2 > 0 结果为假,则不输出任何信息
----------------------------------------------------------------------------
awk -v n=-1 '!++n{print $0}' /etc/passwd
-------------------------------------------------------------------------------------------
awk -v定义了n变量,初始化为-1, 处理/etc/passwd文件数据
处理第一条记录:计算++n ==> n=0 然后计算 !n > !0 > 1 输出第一行信息
处理第二条记录: 计算++n ==> n=1 然后计算 !n > !1 > 0 结果为假,则不输出任何信息
----------------------------------------------------------------------------
awk -v n=-1 '!n++{print $0}' /etc/passwd
----------------------------------------------------------------------------
awk -v定义了n变量,初始化为0, 处理/etc/passwd文件数据
处理第一条记录:计算!n > !-1 > 0 结果为假,则不输出任何信息;最后 n++ ==> n=0
处理第二条记录: 计算!n > !0 > 1 结果为真,输出第二行信息;最后 n++ ==> n=1
----------------------------------------------------------------------------示例
seq 10 | awk -v i=1 'i=!i'
seq 10 | awk -v i=0 'i=!i'
seq 10 | awk '{i=!i;print i}'
seq 10 | awk 'i=!i'
seq 10 | awk '!(i=!i)'
----------------------------------------------------------------------------
seq 10 | awk 'i=!i' 执行结果说明:
第一次:变量i没有初始值,默认为空; !i 结果为真, 则i=1,执行默认动作print $0
第二次:变量i=1, !i 结果为假, 则i=0,不执行任何操作
第三次:变量i=0, !i 结果为真, 则i=1,执行默认动作print $03.5 模式匹配
示例
#匹配/etc/passwd文件中每一行含有root字符串则打印
[root@centos7 ~]#awk -F: '$0 ~/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
#匹配/etc/passwd文件中每一行不含有root字符串则打印
[root@centos7 ~]#awk -F: '$0 !~/root/' /etc/passwd
#匹配/etc/passwd文件中第一列含有root字符串则打印
[root@centos7 ~]#awk -F: '$1 ~/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash3.6 三目运算
awk三目运算和C语言的三目运算相同,当条件为真,则执行操作1,当条件为假,则执行操作2
条件?操作1:操作2
示例
[root@centos7 ~]#awk -F: '{$3>=1000?usertype="Common User":usertype="SysUser";printf "%-20s:%12s\n",$1,usertype}' /etc/passwd
root : SysUser
bin : SysUser
daemon : SysUser
adm : SysUser
lp : SysUser
sync : SysUser
shutdown : SysUser
halt : SysUser
mail : SysUser
operator : SysUser
games : SysUser
ftp : SysUser
nobody : SysUser
systemd-network : SysUser
dbus : SysUser
polkitd : SysUser
postfix : SysUser
sshd : SysUser
chrony : SysUser
rpc : SysUser
rpcuser : SysUser
nfsnobody : Common User
[root@centos7 ~]#df | awk -F"[ %]+" '/^\/dev\/sd/{$(NF-1)>10?disk="full":disk="OK";print $(NF-1),disk}'
5 OK
26 full
[root@centos7 ~]#df -h
文件系统 容量 已用 可用 已用% 挂载点
/dev/sda5 26G 1.2G 25G 5% /
devtmpfs 1.9G 0 1.9G 0% /dev
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 1.9G 8.6M 1.9G 1% /run
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
/dev/sda2 497M 128M 370M 26% /boot
tmpfs 378M 0 378M 0% /run/user/0
/dev/sr0 4.4G 4.4G 0 100% /mnt4、模式PATTERN
PATTERN:根据pattern条件,过滤匹配的行,再做处理
4.1 空模式
空模式:不指定匹配正则信息,则会处理动作:{print $0}
awk -F: '{print $1}' /etc/passwd
4.2 正则匹配模式
正则匹配模式:根据正则表达式匹配数据行,匹配到数据行进行处理,未能匹配到数据行不做任何处理
[root@centos7 ~]#awk '/^UUID/' /etc/fstab
UUID=121b7047-1255-438c-956e-c6118787df36 / xfs defaults 0 0
UUID=9466f144-1056-43d6-aaa4-5205567ea66b /boot xfs defaults 0 0
UUID=08d5cbac-23cb-4121-aaee-309688e55af8 swap swap defaults 0 0
# $0表示打印整行
[root@centos7 ~]#awk '$0 ~ /^UUID/' /etc/fstab
UUID=121b7047-1255-438c-956e-c6118787df36 / xfs defaults 0 0
UUID=9466f144-1056-43d6-aaa4-5205567ea66b /boot xfs defaults 0 0
UUID=08d5cbac-23cb-4121-aaee-309688e55af8 swap swap defaults 0 0
[root@centos7 ~]#awk '! /^UUID/' /etc/fstab
#
# /etc/fstab
# Created by anaconda on Mon Oct 18 21:15:48 2021
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
[root@centos7 ~]#awk '$0 !~ /^UUID/' /etc/fstab
#
# /etc/fstab
# Created by anaconda on Mon Oct 18 21:15:48 2021
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#4.3 表达式模式
表达式模式:只有表达式结果为真,则处理对应数据行,如果表达式结果为假,则不对数据行做任何处理
表达式为真:非0,非空字符串
表达式为假:数字0,或者是空字符串
[root@centos7 ~]#awk '1' /etc/issue
\S
Kernel \r on an \m
[root@centos7 ~]#awk '0' /etc/issue
[root@centos7 ~]#
[root@centos7 ~]#awk '"abc"' /etc/issue
\S
Kernel \r on an \m
[root@centos7 ~]#awk '""' /etc/issue
#打印为空,不加双引号,会把abc当成变量
[root@centos7 ~]#awk 'abc' /etc/issue
[root@centos7 ~]#awk -v abc=123 'abc' /etc/issue
\S
Kernel \r on an \m
[root@centos7 ~]#awk '"0"' /etc/issue
\S
Kernel \r on an \m
[root@centos7 ~]#awk -v abc="" 'abc' /etc/issue
[root@centos7 ~]#awk -v abc=0 'abc' /etc/issue
[root@centos7 ~]#seq 10 | awk '0'
[root@centos7 ~]#seq 10 | awk '1'
[root@centos7 ~]#seq 10 | awk '"gawk"'
[root@centos7 ~]#seq 10 | awk '""'
----------------------------------------------------------------------------
#awk命令,字符串前后不加双引号默认认为是变量名,此时var变量未定义,则为假
seq 10 | awk 'var'
#定义了var变量,但未赋于初始值,则为假
seq 10 | awk -v var= 'var'
#awk命令会把变量值替换到表达式中, 也就是:var="0“ 替换到表达式 '0'
seq 10 | awk -v var="0" 'var'
#变量var值为gawk,不为空字符串,则为真,处理所有数据行
seq 10 | awk -v var="gawk" 'var'示例:
[root@centos7 ~]#awk -F: '$3>=1000{print $1,$3}' /etc/passwd
nfsnobody 65534
[root@centos7 ~]#awk -F: '$3<1000{print $1,$3}' /etc/passwd
[root@centos7 ~]#awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
root /bin/bash
aaa /bin/bash4.4 行模式
awk不支持直接用行号,但可以使用变量NR间接指定行号进行判断处理
[root@centos7 ~]#seq 10 | awk 'NR>=3 && NR<=6'
3
4
5
6
[root@centos7 ~]#seq 10 | sed -n '3,6p';
3
4
5
6
[root@centos7 ~]#awk 'NR>=3 && NR<=6{print NR,$0}' /etc/passwd
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/syncawk也支持sed命令的正则范围匹配,匹配一行信息到另一行信息进行处理,比如:匹配以bin开头的行到以sshd开头的行
[root@centos7 ~]#sed -n '/^bin/,/^sshd/p' /etc/passwd
[root@centos7 ~]#awk '/^bin/,/^sshd/' /etc/passwd
[root@centos7 ~]#awk -v FS=":" '/^bin/,/^sshd/{print $1,FS,$3}' /etc/passwd
bin : 1
daemon : 2
adm : 3
lp : 4
sync : 5
shutdown : 6
halt : 7
mail : 8
operator : 11
games : 12
ftp : 14
nobody : 99
systemd-network : 192
dbus : 81
polkitd : 999
postfix : 89
sshd : 744.5 BEGIN / END 模式
BEGIN模式:仅在开始处理文件中的文本之前执行一次
END模式:仅在文本处理完成之后执行一次
[root@centos7 ~]#awk -F: 'BEGIN{print "用户","UUID","家目录"};{print $1,$3,$(NF-1)}' /etc/passwd|column -t | head -3
用户 UUID 家目录
root 0 /root
bin 1 /bin
[root@centos7 ~]#awk -F: '{print "USER USERID";print $1":"$3} END{print "END FILE"}' /etc/passwd
[root@centos7 ~]#awk -F: 'BEGIN{print "用户","UUID","家目录"};{print $1,$3,$(NF-1)};END{print "数据处理完毕!"}' /etc/passwd|column -t
[root@centos7 ~]#awk -F: 'BEGIN{print "USER UID \n--------------- "}{print $1,$3}' /etc/passwd
[root@centos7 ~]#awk -F: 'BEGIN{print "USER UID \n--------"}{print $1,$3}END{print "=========="}' /etc/passwd
[root@centos7 ~]#awk -F: 'BEGIN{printf "--------------------------------\n%-20s|%10s|\n--------------------------------\n","username","uid"}{printf "%-20s|%10d|\n--------------------------------\n",$1,$3}' /etc/passwd示例:awk计算
awk 'BEGIN{print 10/3}'
awk -v var=10 'BEGIN{print var/3}示例:统计/etc/service文件中的空白行
[root@centos7 ~ ]# egrep "^$" /etc/services|wc -l
17
[root@centos7 ~ ]# awk '/^$/{i=i+1};END{print i}' /etc/services
17示例:统计/etc/services文件中有井号开头的行
[root@centos7 ~ ]# egrep "^#" /etc/services|wc -l
102
[root@centos7 ~ ]# awk -v i=0 '/^#/{i=i+1};END{print i}' /etc/services
102
[root@centos7 ~ ]# awk '/^#/{i++};END{print i}' /etc/services
102示例:统计系统中有多少个虚拟用户和普通用户
[root@centos7 ~ ]# awk -F: -v n=0 -v m=0 'BEGIN{printf "%-20s%-s\n","login_user","nologin_user"};/bash$/{n++};!/bash$/{m++};END{printf "%-20s%s\n",n,m}' /etc/passwd
login_user nologin_user
2 21