awk:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出,GNU/Linux发布的AWK目前由自由软件基金会(FSF)进行开发和维护,通常也称它为 GNU AWK
有多种版本:
gawk:模式扫描和处理语言,可以实现下面功能
格式:
awk [options] 'program' var=value file…
awk [options] -f programfile var=value file…
说明:
program通常是被放在单引号中,并可以由三种部分组成
常见选项:
Program格式:
pattern{action statements;..}
pattern:决定动作语句何时触发及触发事件,比如:BEGIN,END,正则表达式等
action statements:对数据进行处理,放在{}内指明,常见:print, printf
awk 工作过程
第一步:执行BEGIN{action;… }语句块中的语句
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块
分割符、域和记录
$1,$2...$n
称为域标识,$0
为所有域,注意:和shell中变量$符含义不同常用的action分类
awk控制语句
格式:
print item1, item2, ...
说明:
范例:
[root@centos8-B ~]#awk '{print "hello awk"}'
hi
hello awk
wow
hello awk
[root@centos8-B ~]#seq 10 |awk '{print "hello,awk"}'
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
[root@centos8-B ~]#seq 3 |awk '{print 2*3}'
6
6
6
[root@centos8-B ~]#awk -F: '{print "cui"}' /etc/passwd
[root@centos8 ~]#awk -F: '{print}' /etc/passwd
[root@centos8 ~]#awk -F: '{print $0}' /etc/passwd
[root@centos8 ~]#awk -F: '{print $1,$3}' /etc/passwd
[root@centos8 ~]#awk -F: '{print $1"\t"$3}' /etc/passwd
[root@centos8-B ~]#grep "^UUID" /etc/fstab |awk {'print $2,$3'}
/ xfs
/boot ext4
/date xfs
swap swap
面试题:取出网站访问量最大的前3个IP
[root@centos8-B ~]#awk '{print $1}' access_log |sort |uniq -c |sort -nr |head -3
4870 172.20.116.228
3429 172.20.116.208
2834 172.20.0.222
[root@centos8-B ~]#awk '{print $1}' access_log |sort |uniq -c |sort -nr |head
4870 172.20.116.228
3429 172.20.116.208
2834 172.20.0.222
2613 172.20.112.14
2267 172.20.0.227
2262 172.20.116.179
2259 172.20.65.65
1565 172.20.0.76
1482 172.20.0.200
1110 172.20.28.145
面试题:取出分区利用率
[root@centos8-B ~]#df |awk '{print $1,$5}'
Filesystem Use%
devtmpfs 0%
tmpfs 0%
tmpfs 1%
tmpfs 0%
/dev/sda2 11%
/dev/sda5 1%
/dev/sda1 19%
tmpfs 1%
#使用扩展的正则表达式
[root@centos8-B ~]#df |awk -F"[[:space:]]++|%" '{print $5}'
Use
0
0
1
0
11
1
19
1
[root@centos8-B ~]#df |awk -F"[[:space:]]++|%" '{print $1,$5}'
Filesystem Use
devtmpfs 0
tmpfs 0
tmpfs 1
tmpfs 0
/dev/sda2 11
/dev/sda5 1
/dev/sda1 19
tmpfs 1
[root@centos8-B ~]#df |awk -F" ++|%" '{print $1,$5}'
Filesystem Use
devtmpfs 0
tmpfs 0
tmpfs 1
tmpfs 0
/dev/sda2 11
/dev/sda5 1
/dev/sda1 19
tmpfs 1
[root@centos8-B ~]#df |grep '^/dev/sd' |awk -F" ++|%" '{print $1,$5}'
/dev/sda2 11
/dev/sda5 1
/dev/sda1 19
[root@centos8-B ~]#df |grep '^/dev/sd' |awk -F" ++|%" '{print $5}'
11
1
19
[root@centos8-B ~]#df |awk -F" ++|%" '/^\/dev\/sd/{print $1,$5}'
/dev/sda2 11
/dev/sda5 1
/dev/sda1 19
[root@centos8-B ~]#df |awk -F" ++|%" '/^\/dev\/sd/{print $5}'
11
1
19
面试题:取 ifconfig 输出结果中的IP地址
[root@centos8-B ~]#ifconfig eth0 |awk '/netmask/{print $2}'
10.0.0.10
[root@centos6 ~]#ifconfig eth0 |awk -F" +|:" '/Mask/{print $4}'
10.0.0.6
[root@centos8-B ~]#ifconfig eth0 |sed -rn "2s/^[^0-9]+([0-9.]+) .*$/\1/p"
10.0.0.10
[root@centos6 ~]#ifconfig eth0 |sed -rn "2s/^[^0-9]+([0-9.]+) .*$/\1/p"
10.0.0.6
面试题:文件host_list.log 如下格式,请提取”.magedu.com”前面的主机名部分并写入到回到该文件中
[root@centos8-B ~]#cat host_list.log
1 www.magedu.com
2 blog.magedu.com
3 study.magedu.com
4 linux.magedu.com
5 python.magedu.com
[root@centos8-B ~]#awk -F"[ .]" '{print $2}' host_list.log
www
blog
study
linux
python
[root@centos8-B ~]#awk -F"[ .]" '{print $2}' host_list.log >> host_list.log
[root@centos8-B ~]#cat host_list.log
1 www.magedu.com
2 blog.magedu.com
3 study.magedu.com
4 linux.magedu.com
5 python.magedu.com
www
blog
study
linux
python
awk中的变量分为:内置和自定义变量
常见的内置变量
FS:输入自动分隔符,默认为空白字符;
OFS:输出自动分隔符,默认为空白字符;
RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效;
ORS:输出记录分隔符,输出时用指定符号代替换行符;
NF:字段数量;
NR:行号;
FNR:各文件分别计数,记录号;
FILENAME:当前文件名;
ARGC:命令行参数的个数;
ARGV:数组,保存的是命令行所给定的各参数。
范例:
awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
awk -v FS=":" '{print $1FS$3}' /etc/passwd
awk -F: '{print $1,$3,$7}' /etc/passwd
S=:;awk -v FS=$S '{print $1FS$3}' /etc/passwd
[root@centos8-B ~]#awk -v FS=":" '{print $1FS$3}' /etc/passwd |head -n3
root:0
bin:1
daemon:2
[root@centos8-B ~]#S=:;awk -v FS=$S '{print $1FS$3}' /etc/passwd |head -n3
root:0
bin:1
daemon:2
#-F 和 FS变量功能一样,同时使用会冲突
[root@centos8-B ~]#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@centos8-B ~]#awk -F";" -v FS=":" '{print $1FS$3}' /etc/passwd |head -n3
root:0
bin:1
daemon:2
范例:
[root@centos8-B ~]#awk -v FS=":" '{print $1,$3,$7}' /etc/passwd |head -n1
root 0 /bin/bash
[root@centos8-B ~]#awk -v FS=":" -v OFS=":" '{print $1,$3,$7}' /etc/passwd |head -n1
root:0:/bin/bash
范例:
awk -v RS=' ' '{print }' /etc/passwd
范例:
awk -v RS=' ' -v ORS='###' '{print $0}' /etc/passwd
范例:
#引用变量时,变量前不需加$
[root@centos8-B ~]#awk -F: '{print NF}' /etc/fstab
[root@centos8-B ~]#awk -F: '{print $(NF-1)}' /etc/passwd
[root@centos8-B ~]#ls /mnt/BaseOS/Packages/*.rpm |awk -F"." '{print $(NF-1)}' |sort |uniq -c
389 i686
208 noarch
1060 x86_64
面试题:连接数最多的前3个IP
[root@centos8-B ~]#awk -F" +|:" '{print $(NF-2)}' ss.log |sort |uniq -c |sort -nr |head -n3
44 127.0.0.1
10 113.234.28.244
8 124.64.18.135
[root@centos8-B ~]#awk -F" +|:" '/^ESTAB/{print $(NF-2)}' ss.log |sort |uniq -c |sort -nr |head -n3
44 127.0.0.1
10 113.234.28.244
8 124.64.18.135
[root@centos8-B ~]#ss -nt |grep "^ESTAB" |awk -F"[[:space:]]+|:" '{print $(NF -2)}'
10.0.0.1
10.0.0.7
10.0.0.1
[root@centos8-B ~]#ss -nt |awk -F"[[:space:]]+|:" '/^ESTAB/{print $(NF -2)}'
10.0.0.1
10.0.0.7
10.0.0.1
[root@centos8-B ~]#ss -nt |awk -F: '{print $(NF -1)}' |awk '/^[0-9]/{print $NF}' |sort |uniq -c |head -n3
2 10.0.0.1
范例:每十分钟检查将连接数超过100个以上的IP放入黑名单拒绝访问
[root@centos8 ~]#cat deny_dos.sh
LINK=100
while true;do
ss -nt | awk -F"[[:space:]]+|:" '/^ESTAB/{print $(NF-2)}'|sort |uniq - c|while 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
范例:
[root@centos8 ~]#cat deny_dos.sh
IPLIST=`awk -F" +|:" '/^ESTAB/{print $(NF-2)}' ss.log |sort |uniq -c|sort -
nr|head -3|awk '{print $2}'`
for ip in $IPLIST;do
iptables -A INPUT -s $ip -j REJECT
done
范例:
[root@centos8-B ~]#awk '{print NR,$0}' /etc/issue /etc/centos-release
1 \S
2 Kernel \r on an \m
3
4 CentOS Linux release 8.0.1905 (Core)
范例:取ifconfig输出结果中的IP地址
[root@centos8-B ~]#ifconfig eth0 |awk '/netmask/{print $2}'
10.0.0.10
[root@centos8-B ~]#ifconfig eth0 |awk 'NR==2{print $2}'
10.0.0.10
范例:
[root@centos8 ~]#awk -F: '{print NR}' /etc/passwd
123
......
[root@centos8 ~]#awk -F: 'END{print NR}' /etc/passwd
57
[root@centos8 ~]#awk -F: 'BEGIN{print NR}' /etc/passwd
0
范例:
awk '{print FNR}' /etc/fstab /etc/inittab
[root@centos8-B ~]#awk '{print NR,$0}' /etc/issue /etc/redhat-release
1 \S
2 Kernel \r on an \m
3
4 CentOS Linux release 8.0.1905 (Core)
[root@centos8-B ~]#awk '{print FNR,$0}' /etc/issue /etc/redhat-release
1 \S
2 Kernel \r on an \m
3
1 CentOS Linux release 8.0.1905 (Core)
范例:
[root@centos8-B ~]#awk '{print FILENAME}' /etc/issue
/etc/issue
/etc/issue
/etc/issue
[root@centos8-B ~]#awk '{print FNR,FILENAME,$0}' /etc/issue /etc/redhat-release
1 /etc/issue \S
2 /etc/issue Kernel \r on an \m
3 /etc/issue
1 /etc/redhat-release CentOS Linux release 8.0.1905 (Core)
范例:
[root@centos8-B ~]#awk '{print ARGC}' /etc/issue /etc/redhat-release
3
3
3
3
[root@centos8-B ~]#awk 'BEGIN{print ARGC}' /etc/issue /etc/redhat-release
3
范例:
[root@centos8 ~]#awk 'BEGIN{print ARGV[0]}' /etc/issue /etc/redhat-release
awk
[root@centos8 ~]#awk 'BEGIN{print ARGV[1]}' /etc/issue /etc/redhat-release
/etc/issue
[root@centos8 ~]#awk 'BEGIN{print ARGV[2]}' /etc/issue /etc/redhat-release
/etc/redhat-release
[root@centos8 ~]#awk 'BEGIN{print ARGV[3]}' /etc/issue /etc/redhat-release
[root@centos8 ~]#
自定义变量(区分字符大小写)
范例:
[root@centos8-B ~]#awk -F: -v name='username:' '{print name,$1}' awktest.txt
username: root
username: bin
username: daemon
username: adm
username: lp
username: sync
username: shutdown
username: halt
username: mail
username: operator
[root@centos8-B ~]#awk -v test='hello gawk' '{print test}' /etc/fstabhello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
[root@centos8-B ~]#awk -v test='hello gawk' 'BEGIN{print test}'
hello gawk
[root@centos8-B ~]#awk 'BEGIN{test="hello,gawk";print test}'
hello,gawk
[root@centos8-B ~]#awk -F: '{sex="male";print $1,sex,age;age=18}' awktest.txt
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
[root@centos8-B ~]#echo '{name="mmagedu";age=20;print name,$1,age}' > awkscript
[root@centos8-B ~]#cat awkscript
{name="mmagedu";age=20;print name,$1,age}
[root@centos8-B ~]#awk -F: -f awkscript awktest.txt
mmagedu root 20
mmagedu bin 20
mmagedu daemon 20
mmagedu adm 20
mmagedu lp 20
mmagedu sync 20
mmagedu shutdown 20
mmagedu halt 20
mmagedu mail 20
mmagedu operator 20
cat awkscript
{print script,$1,$2}
awk -F: -f awkscript script="awk" /etc/passwd
printf 可以实现格式化输出
格式:
printf “FORMAT”, item1, item2, ...
说明:
格式符:与item一一对应
修饰符
#[.#] 第一个数字控制显示的宽度;第二个#表示小数点后精度,如:%3.1f
- 左对齐(默认右对齐) 如:%-15s
+ 显示数值的正负符号 如:%+d
范例:
awk -F: '{printf "%s",$1}' /etc/passwd
awk -F: '{printf "%s\n",$1}' /etc/passwd
awk -F: '{printf "%20s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %s\n",$1}' /etc/passwd
awk -F: '{printf “Username: %sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %25sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %-25sUID:%d\n",$1,$3}' /etc/passwd
[root@centos8-B ~]#awk -F: '{printf "%20s %10d\n",$1,$3}' awktest.txt root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
[root@centos8-B ~]#awk -F: '{printf "%-20s %10d\n",$1,$3}' awktest.txt
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
#以冒号为分隔符,每行输出”username:第一个字段“,然后换行
[root@centos8-B ~]#awk -F: '{printf "username:%s\n",$1}' awktest.txt
username:root
username:bin
username:daemon
username:adm
username:lp
username:sync
username:shutdown
username:halt
username:mail
username:operator
#以冒号为分隔符,每行输出”username:第一个字段,左对齐,占20个宽度,UID:第三个字段“,然后换行
[root@centos8-B ~]#awk -F: '{printf "username:%-20s uid:%d\n",$1,$3}' awktest.txt
username:root uid:0
username:bin uid:1
username:daemon uid:2
username:adm uid:3
username:lp uid:4
username:sync uid:5
username:shutdown uid:6
username:halt uid:7
username:mail uid:8
username:operator uid:11
算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x:转换为负数
+x:将字符串转换为数值
字符串操作符:没有符号的操作符,字符串连接
赋值操作符:
=:右边赋值给左边
+=:先加,再赋值
-=:先减,再赋值
*=:先乘,再赋值
/=:先除,再赋值
%=:先取余,再赋值
^=:先幂运算,再赋值
++:递增操作
--:递减操作
范例:
[root@centos8 ~]#awk 'BEGIN{i=0;print i++,i}' #先赋值再加
0 1
[root@centos8 ~]#awk 'BEGIN{i=0;print ++i,i}' #先加再赋值
1 1
范例:
[root@centos8 ~]#awk -v n=0 '!n++' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@centos8 ~]#awk -v n=0 '!n++{print n}' /etc/passwd
1
[root@centos8 ~]#awk -v n=1 '!n++{print n}' /etc/passwd
[root@centos8 ~]#awk -v n=0 '!++n{print n}' /etc/passwd
[root@centos8 ~]#awk -v n=0 '!++n' /etc/passwd
[root@centos8 ~]#awk -v n=-1 '!++n' /etc/passwd
root:x:0:0:root:/root:/bin/bash
比较操作符:
==:判断相等
!=:判断不等
\>:判断大于
\>=:判断大于等于
<:判断小于
<=:判断小于等于
范例:
[root@centos8 ~]#awk 'NR==2' /etc/issue
Kernel \r on an \m
[root@centos8 ~]#awk -F: '$3>=1000' /etc/passwd
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
wang:x:1000:1000:wang:/home/wang:/bin/bash
mage:x:1001:1001::/home/mage:/bin/bash
范例:取奇,偶数行
[root@centos8 ~]#seq 10 | awk 'NR%2==0'
2
4
6
8
10
[root@centos8 ~]#seq 10 | awk 'NR%2==1'
1
3
5
7
9
[root@centos8 ~]#seq 10 | awk 'NR%2!=0'
1
3
5
7
9
模式匹配符:
~ 左边是否和右边匹配,包含关系
!~ 是否不匹配
范例:
[root@centos8-B ~]#awk -F: '$0 ~ /root/{print $0}' awktest.txt
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@centos8-B ~]#awk -F: '$0 !~ /root/{print $0}' awktest.txt
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
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
[root@centos8 ~]#awk -F: '$0 ~ "^root"{print $1}' /etc/passwd
root
[root@centos8 ~]#awk '$0 !~ /root/' /etc/passwd
[root@centos8 ~]#awk '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@centos8 ~]#awk -F: '$3==0' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@centos8 ~]#df | awk -F"[[:space:]]+|%" '$0 ~ /^\/dev\/sd/{print $5}'
11
1
19
[root@centos8 ~]#ifconfig eth0 | awk 'NR==2{print $2}'
10.0.0.8
逻辑操作符:
与:&&,并且关系
或:||,或者关系
非:!,取反
范例:!取反
[root@centos8 ~]#awk 'BEGIN{print i}'
[root@centos8 ~]#awk 'BEGIN{print !i}'
1
[root@centos8 ~]#awk -v i=10 'BEGIN{print !i}'
0
[root@centos8 ~]#awk -v i=-3 'BEGIN{print !i}'
0
[root@centos8 ~]#awk -v i=0 'BEGIN{print !i}'
1
[root@centos8 ~]#awk -v i=abc 'BEGIN{print !i}'
0
[root@centos8 ~]#awk -v i='' 'BEGIN{print !i}'
1
[root@centos8-B ~]#seq 10 |awk 'i=!i'
1
3
5
7
9
[root@centos8-B ~]#seq 10 |awk '!(i=!i)'
2
4
6
8
10
范例:
awk -F: '$3>=0 && $3<=1000 {print $1,$3}' /etc/passwd
awk -F: '$3==0 || $3>=1000 {print $1,$3}' /etc/passwd
awk -F: '!($3==0) {print $1,$3}' /etc/passwd
awk -F: '!($3>=500) {print $1,$3}' /etc/passwd
条件表达式(三目表达式)
selector?if-true-expression:if-false-expression
范例:
[root@centos8-B ~]#awk -F: '{$3>=500?typeuser="common user":typeuser="sysuser" ;printf "%-15s %-20s %10d\n",typeuser,$1,$3}' awktest.txt
sysuser root 0
sysuser bin 1
sysuser daemon 2
sysuser adm 3
sysuser lp 4
sysuser sync 5
sysuser shutdown 6
sysuser halt 7
sysuser mail 8
sysuser operator 11
PATTERN:根据pattern条件,过滤匹配的行,再做处理
PATTERN:根据pattern条件,过滤匹配的行,再做处理:
1. 如果未指定:空模式,匹配每一行;
2. /regular expression/:仅处理能够模式匹配到的行,需要用//扩起来;
3. relational expression:关系表达式,结果为真,才会被处理;
真:结果为非0值,非空字符串都是真;
假:结果为空字符串或0值都是假。
4. line ranges:行范围;
startine,endline:/pat1/,/pat2/不支持直接给出数子格式。
5. BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次;
END{}:仅在文本处理完成之后执行一次。
[root@centos8 ~]#awk -F: '{print $1,$3}' /etc/passwd
[root@centos8 ~]#awk '/^UUID/{print $1}' /etc/fstab
[root@centos8 ~]#awk '!/^UUID/{print $1}' /etc/fstab
[root@centos8 ~]#df | awk '/^\/dev\/sd/'
/dev/sda2 104806400 4935924 99870476 5% /
/dev/sda3 52403200 398876 52004324 1% /data
/dev/sda1 999320 848572 81936 92% /boot
范例:
[root@centos8 ~]#awk '!1' /etc/passwd
[root@centos8 ~]#awk '!0' /etc/passwd
root:x:0:0:root:/root:/bin/bash
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
.......
[root@centos8 ~]#awk '1' /etc/issue
\S
Kernel \r on an \m
[root@centos8 ~]#awk '0' /etc/issue
[root@centos8 ~]#awk '"magedu"' /etc/issue
\S
Kernel \r on an \m
[root@centos8 ~]#awk '""' /etc/issue
[root@centos8 ~]#awk 'magedu' /etc/issue
[root@centos8 ~]#awk 'magedu' /etc/issue
[root@centos8 ~]#awk -v magedu=wang 'magedu' /etc/issue
\S
Kernel \r on an \m
[root@centos8 ~]#awk -v magedu="" 'magedu' /etc/issue
[root@centos8 ~]#awk -v magedu="0" 'magedu' /etc/issue
[root@centos8 ~]#awk -v magedu=0 'magedu' /etc/issue
[root@centos8 ~]#awk '"0"' /etc/issue
\S
Kernel \r on an \m
[root@centos8 ~]#awk '0' /etc/issue
范例:
awk -F: 'i=1;j=1{print i,j}' /etc/passwd
awk -F: '$3>=1000{print $1,$3}' /etc/passwd
awk -F: '$3<1000{print $1,$3}' /etc/passwd
awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
[root@centos8 ~]#awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
root /bin/bash
wang /bin/bash
mage /bin/bash
[root@centos8 ~]#awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd
root /bin/bash
wang /bin/bash
mage /bin/bash
不支持直接用行号,但可以使用变量NR间接指定行号
/pat1/,/pat2/ 不支持直接给出数字格式
范例:
[root@centos8 ~]#seq 10 | awk 'NR>=3 && NR<=6'
3
4
5
6
[root@centos8 ~]#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/sync
[root@centos8 ~]#sed -n '3,6p' /etc/passwd
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@centos8 ~]#awk '/^bin/,/^adm/' /etc/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
[root@centos8 ~]#sed -n '/^bin/,/^adm/p' /etc/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
BEGIN{}:仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
范例
awk -F : 'BEGIN {print "USER USERID"} {print $1":"$3} END{print "END FILE"}'
/etc/passwd
awk -F: '{print "USER USERID";print $1":"$3} END{print "END FILE"}' /etc/passwd
awk -F: 'BEGIN{print "USER UID \n--------------- "}{print $1,$3}' /etc/passwd
awk -F: 'BEGIN{print "USER UID \n--------"}{print $1,$3}END{print
"=========="}' /etc/passwd
[root@centos8-B ~]#awk -F: 'BEGIN{print "user id\n----------------------"}{printf "%-10s| %10d\n", $1,$3}END{print "----------------------"}' awktest.txt
user id
----------------------
root | 0
bin | 1
daemon | 2
adm | 3
lp | 4
sync | 5
shutdown | 6
halt | 7
mail | 8
operator | 11
----------------------
范例:
seq 10 | awk 'i=0'
seq 10 | awk 'i=1'
seq 10 | awk 'i=!i'
seq 10 | awk '{i=!i;print i}'
seq 10 | awk '!(i=!i)'
seq 10 | awk -v i=1 'i=!i'
[root@centos8-B ~]#seq 10 |awk 'i=0'
[root@centos8-B ~]#
[root@centos8-B ~]#seq 10 |awk 'i=1'
1
2
3
4
5
6
7
8
9
10
[root@centos8-B ~]#seq 10 |awk 'i=!i'
1
3
5
7
9
[root@centos8-B ~]#seq 10 |awk '!(i=!i)'
2
4
6
8
10
[root@centos8-B ~]#seq 10 |awk -v i=1 'i=!i'
2
4
6
8
10
[root@centos8-B ~]#seq 10 |awk -v i=0 'i=!i'
1
3
5
7
9
[root@centos8-B ~]#seq 10 |awk '{i=!i;print i}'
1
0
1
0
1
0
1
0
1
0
语法:
if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else if(condition3)
{statement3}......else{statementN}
使用场景:对awk取得的整行或某个字段做条件判断
范例:
awk -F: '{if($3>=1000)print $1,$3}' /etc/passwd
awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
awk '{if(NF>5) print $0}' /etc/fstab
awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or
Sysuser: %s\n",$1}}' /etc/passwd
awk -F: '{if($3>=1000) printf "Common user: %s\n",$1; else printf "root or
Sysuser: %s\n",$1}' /etc/passwd
df -h|awk -F% '/^\/dev\/sd/{print $1}'| awk '$NF>=80{print $1,$5}'
df | awk -F"[[:space:]]+|%" '/^\/dev\/sd/{if($5>80)print $1,$5}'
[root@centos8 ~]#df | awk -F' +|%' '/^\/dev\/sd/{if($5>=10)print $1,$5}'
/dev/sda1 15
awk 'BEGIN{ test=100;if(test>90){print "very good"}
else if(test>60){ print "good"}else{print "no pass"}}'
语法:
switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or
/REGEXP2/: statement2; ...; default: statementn}
条件“真”,进入循环;条件“假”,退出循环
使用场景:
示例:
#内置函数length()返回字符数,而非字节数
[root@centos8-B ~]#awk 'BEGIN{print length("hello")}'
5
[root@centos8-B ~]#awk 'BEGIN{print length("马哥教育")}'
4
[root@Centos7 ~]#awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i);i++}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-1127.el7.x86_64 31
root=UUID=eeb6c8d3-c590-4cb0-9d48-8c2cc415c933 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
linux16 7
/vmlinuz-0-rescue-440a03bbbe024e0287063cec5bb90e06 50
root=UUID=eeb6c8d3-c590-4cb0-9d48-8c2cc415c933 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
[root@Centos7 ~]#awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){if(length($i)>=10){print $i,length($i)};i++}}' /etc/grub2.cfg
/vmlinuz-3.10.0-1127.el7.x86_64 31
root=UUID=eeb6c8d3-c590-4cb0-9d48-8c2cc415c933 46
crashkernel=auto 16
net.ifnames=0 13
/vmlinuz-0-rescue-440a03bbbe024e0287063cec5bb90e06 50
root=UUID=eeb6c8d3-c590-4cb0-9d48-8c2cc415c933 46
crashkernel=auto 16
net.ifnames=0 13
#计算1+2+3+...+100
[root@Centos7 ~]#awk 'BEGIN{ total=0;i=1;while(i<=100){total+=i;i++};print total}'
5050
语法:
do {statement;…}while(condition)
意义:无论真假,至少执行一次循环体
范例:
[root@Centos7 ~]#awk 'BEGIN{ total=0;i=1;do{ total+=i;i++;}while(i<=100);print total}'
5050
语法:
for(expr1;expr2;expr3) {statement;…}
常见用法:
for(variable assignment;condition;iteration process) {for-body}
特殊用法:能够遍历数组中的元素
for(var in array) {for-body}
范例:
[root@centos8 ~]#awk 'BEGIN{total=0;for(i=1;i<=100;i++){total+=i};print total}'
5050
范例:
[root@Centos7 ~]#awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++){print $i,length($i)}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-1127.el7.x86_64 31
root=UUID=eeb6c8d3-c590-4cb0-9d48-8c2cc415c933 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
linux16 7
/vmlinuz-0-rescue-440a03bbbe024e0287063cec5bb90e06 50
root=UUID=eeb6c8d3-c590-4cb0-9d48-8c2cc415c933 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
性能比较
time (awk 'BEGIN{ total=0;for(i=0;i<=10000;i++){total+=i;};print total;}')
time (total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)
time (for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)
time (seq –s ”+” 10000|bc)
continue 中断本次循环
break 中断整个循环
格式:
continue [n]
break [n]
范例:
[root@centos8-B ~]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}'
2500
[root@centos8-B ~]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==50)break;sum+=i}print sum}'
1225
next 可以提前结束对本行处理而直接进入下一行处理(awk自身循环)
范例:
[root@centos8-B ~]#awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
root 0
daemon 2
lp 4
shutdown 6
mail 8
games 12
ftp 14
nobody 65534
polkitd 998
rtkit 172
unbound 996
rpc 32
chrony 994
saslauth 992
dnsmasq 986
cockpit-ws 984
sssd 982
pipewire 980
gdm 42
insights 978
sshd 74
avahi 70
tcpdump 72
cui 1000
awk的数组为关联数组
格式
array_name[index-expression]
范例:
weekdays["mon"]="Monday"
index-expression
范例:
[root@centos8-B ~]#awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]=Tuesday;print weekdays["mon"]}'
Monday
范例:
awk '!line[$0]++' dupfile
awk '{!line[$0]++;print $0, line[$0]}' dupfile
范例:判断数组索引是否存在
[root@centos8-B ~]#awk 'BEGIN{array["i"]="x";array["j"]="y" ;if("i" in array ){print "存在"}else{print "不存在"}}'
存在
[root@centos8-B ~]#awk 'BEGIN{array["i"]="x";array["j"]="y" ;if("abc" in array ){print "存在"}else{print "不存在"}}'
不存在
若要遍历数组中的每个元素,要使用for循环
for(var in array) {for-body}
注意:var会遍历array的每个索引
范例:遍历数组
[root@centos8-B ~]#awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays){print weekdays[i]}}'
Tuesday
Monday
[root@centos8-B ~]#awk 'BEGIN{students[1]="daizong";students[2]="junzong";students[3]="kunzong";for(x in students){print x":"students[x]}}'
1:daizong
2:junzong
3:kunzong
[root@centos8-B ~]#awk 'BEGIN {
> a["x"] = "welcome"
> a["y"] = "to"
> a["z"] = "Magedu"
> for (i in a) {
> print i,a[i]
> }
> }'
x welcome
y to
z Magedu
[root@centos8-B ~]#awk -F: '{user[$1]=$3}END{for(i in user){print "username:"i,"uid: "user[i]}}' /etc/passwd
username:adm uid: 3
username:rpc uid: 32
username:dnsmasq uid: 986
username:radvd uid: 75
username:sync uid: 5
username:mail uid: 8
username:tss uid: 59
username:gluster uid: 995
username:unbound uid: 996
username:halt uid: 7
面试题:显示主机的连接状态出现的次数
[root@centos8-B ~]#awk 'NR!=1{print $1}' ss.log |sort |uniq -c
108 ESTAB
1 FIN-WAIT-1
3 LAST-ACK
[root@centos8-B ~]#cat ss.log | sed -nr '1!s/^([^0-9]+) .*/\1/p'|sort |uniq -c
108 ESTAB
3 LAST-ACK
[root@centos8-B ~]#ss -ant | awk 'NR!=1{state[$1]++}END{for(i in state){print i,state[i]}}'
LISTEN 10
ESTAB 1
[root@centos8-B ~]#netstat -tan | awk '/^tcp/{state[$NF]++}END{for(i in state){print i,state[i]}}'
LISTEN 10
ESTABLISHED 1
范例:
[root@centos8-B ~]#awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' access_log
172.20.0.200 1482
172.20.21.121 2
172.20.30.91 29
172.16.102.29 864
172.20.0.76 1565
172.20.9.9 15
172.20.1.125 463
172.20.61.11 2
[root@centos8-B ~]#awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' access_log |sort -k2 -nr |head -3
172.20.116.228 4870
172.20.116.208 3429
172.20.0.222 2834
[root@centos8-B ~]#awk '{ip[$1]++}END{for(i in ip){print ip[i],i}}' access_log |sort -nr |head -3
4870 172.20.116.228
3429 172.20.116.208
2834 172.20.0.222
面试题:封掉查看访问日志中连接次数超过1000次的IP
awk '{ip[$1]++}END{for(i in ip){if(ip[i]>=1000){system("iptables -A INPUT -s "i" -j REJECT")}}}' access_log
范例:多维数组(了解)
[root@centos8 ~]#awk 'BEGIN{
> array[1][1]=11
> array[1][2]=12
> array[1][3]=13
> array[2][1]=21
> array[2][2]=22
> array[2][3]=23
> for (i in array)
> for (j in array[i])
> print array[i][j]
> }'
11
12
13
21
22
23
awk 的函数分为内置和自定义函数
数值处理:
范例:
[root@centos8 ~]#awk 'BEGIN{srand();print rand()}'
0.790437
[root@centos8 ~]#awk 'BEGIN{srand();print rand()}'
0.283736
[root@centos8 ~]#awk 'BEGIN{srand();print rand()}'
0.948082
[root@centos8 ~]#awk 'BEGIN{srand();print rand()}'
0.371798
[root@centos8-B ~]#awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100)}'
47
97
61
44
88
88
18
41
33
27
字符串处理:
范例:
[root@centos8 ~]#echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
2008-08:08 08:08:08
[root@centos8 ~]#echo "2008:08:08 08:08:08" | awk '{sub(/:/,"-",$1);print $0}'
2008-08:08 08:08:08
gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
范例:
[root@centos8 ~]#echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$0)'
2008-08-08 08-08-08
[root@centos8 ~]#echo "2008:08:08 08:08:08" | awk '{gsub(/:/,"-",$0);print $0}'
2008-08-08 08-08-08
split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2,…
范例:
[root@centos8-B ~]#netstat -tn | awk '/^tcp/{split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}
10.0.0.1 1
10.0.0.6 1
10.0.0.7 673
system 函数:可以awk中调用shell命令
空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其他一律用""引用起来
自定义函数格式:
function name ( parameter, parameter, ... ) {
statements
return expression
}
范例:
[root@centos8 ~]#cat func.awk
function max(x,y) {
x>y?var=x:var=y
return var
}
BEGIN{print max(a,b)}
[root@centos8 ~]#awk -v a=30 -v b=20 -f func.awk
30
将awk程序写成脚本,直接调用或执行
范例
[root@centos8 ~]#cat passwd.awk
{if($3>=1000)print $1,$3}
[root@centos8 ~]#awk -F: -f passwd.awk /etc/passwd
nobody 65534
wang 1000
mage 1001
范例:
[root@centos8 ~]#cat test.awk
#!/bin/awk -f
#this is a awk script
{if($3>=1000)print $1,$3}
[root@centos8 ~]#chmod +x test.awk
[root@centos8 ~]#./test.awk -F: /etc/passwd
nobody 65534
wang 1000
mage 1001
向awk脚本传递参数
格式:
awkfile var=value var2=value2... Inputfile
==注意:==在BEGIN过程中不可用。直到首行输入完成以后,变量才可用。可以通过-v 参数,让awk在执行BEGIN之前得到变量的值。命令行中每一个指定的变量都需要一个-v参数
范例:
[root@centos8 ~]#cat test2.awk
#!/bin/awk -f
{if($3 >=min && $3<=max)print $1,$3}
[root@centos8 ~]#chmod +x test2.awk
[root@centos8 ~]#./test2.awk -F: min=100 max=200 /etc/passwd
systemd-resolve 193
rtkit 172
pulse 171
qemu 107
usbmuxd 113
abrt 173
练习
1、文件host_list.log 如下格式,请提取”.magedu.com”前面的主机名部分并写入到回到该文件中
1 www.magedu.com
2 blog.magedu.com
3 study.magedu.com
4 linux.magedu.com
5 python.magedu.com
......
999 study.magedu.com
2、统计/etc/fstab文件中每个文件系统类型出现的次数
3、统计/etc/fstab文件中每个单词出现的次数
4、提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中的所有数字
5、有一文件记录了1-100000之间随机的整数共5000个,存储的格式100,50,35,89…请取出其中最大和最小的整数
6、解决Dos攻击生产案例:根据web日志或者或者网络连接数,监控当某个IP并发连接数或者短时内PV达到100,即调用防火墙命令封掉对应的IP,监控频率每隔5分钟。防火墙命令为:iptables -A INPUT -s IP -j REJECT
7、将以下文件内容中FQDN取出并根据其进行计数从高到低排序
http://mail.magedu.com/index.html
http://www.magedu.com/test.html
http://study.magedu.com/index.html
http://blog.magedu.com/index.html
http://www.magedu.com/images/logo.jpg
http://blog.magedu.com/20080102.html
http://www.magedu.com/images/magedu.jpg
参考答案:
[root@centos8 ~]#awk -F"/" '{url[$3]++}END{for(i in url){print url[i],i}}'
url.log |sort -nr
3 www.magedu.com
2 blog.magedu.com
1 study.magedu.com
1 mail.magedu.com
8、将以下文本以inode为标记,对inode相同的counts进行累加,并且统计出同一inode中,
beginnumber的最小值和endnumber的最大值
inode|beginnumber|endnumber|counts|
106|3363120000|3363129999|10000|
106|3368560000|3368579999|20000|
310|3337000000|3337000100|101|
310|3342950000|3342959999|10000|
310|3362120960|3362120961|2|
311|3313460102|3313469999|9898|
311|3313470000|3313499999|30000|
311|3362120962|3362120963|2|
输出的结果格式为:
310|3337000000|3362120961|10103|
311|3313460102|3362120963|39900|
106|3363120000|3368579999|30000|