文本三剑客之AWK
awk简介
AWK是一种优良的文本处理工具。它不仅是 Linux中也是任何环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最大功能取决于一个人所拥有的知识。AWK 提供了极其强大的功能:可以进行样式装入、流控制、数学运算符进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上 AWK 的确拥有自己的语言:AWK 程序设计语言, 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
awk是一个强大的文本分析工具,与grep(查找)、sed(编辑)一并称为“文本处理三剑客”。awk最强大的功能是对数据分析并生成报告。
awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk是AWK的GNU版本。
工作原理
第一步:执行BEGIN{action;… }语句块中的语句
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这 个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个 可选的语句块,比如变量初始化、打印输出表格的表头等语句通常 可以写在BEGIN语句块中
END语句块在awk从输入流中读取完所有的行之后即被执行,比如 打印所有行的分析结果这类信息汇总都是在END语句块中完成,它 也是一个可选语句块
pattern语句块中的通用命令是最重要的部分,也是可选的。如果 没有提供pattern语句块,则默认执行{ print },即打印每一个读取 到的行,awk读取的每一行都会执行该语句块
分割符、域和记录
awk执行时,由分隔符分隔的字段(域)标记$1,$2..$n称 为域标识。$0为所有域,注意:和shell中变量$符含义不同
文件的每一行称为记录
省略action,则默认执行 print $0 的操作
步骤
-
执行BEGIN{action;…}
BEGIN在输入之前执行,通常用来打印表头,变量初始化。 -
读取,执行pattern{action;…}
默认执行{ print } -
执行END{action;…}
读取到打印结束后执行,通常用作分析结果,信息汇总
AWK语法基本格式:
基本格式:awk [options] 'program' file…
选项[options]:
-F 指明输入时用到的字段分隔符
-v var=value: 自定义变量
-f:调用awk脚本
program:pattern{action statements;..}
语句之间用分号分割
pattern和action:
pattern:部分决定动作语句何时触发及触发事件 BEGIN,END (触发条件)
action statements:对数据进行处理,放在{}内指明 print, printf (对数据处理动作)
program通常是被单引号或双引号中
知识点整理
1、print
要点:
(1) 逗号分隔符
(2) 输出的各item可以字符串,也可以是数值;当前记录的字段、 变量或awk的表达式
(3) 如省略item,相当于print $0
示例:
[root@centos7 ~]# tail -3 /etc/fstab #源文件 UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0 UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0 UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0 [root@centos7 ~]# tail -3 /etc/fstab |awk '{print}' UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0 UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0 UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0 [root@centos7 ~]# tail -3 /etc/fstab |awk '{print "wang"}' wang wang wang [root@centos7 ~]# tail -3 /etc/fstab |awk '{print $0}' UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0 UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0 UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0 [root@centos7 ~]# tail -3 /etc/fstab |awk '{print $2$4}' /appdefaults /bootdefaults swapdefaults、 [root@centos7 ~]# tail -3 /etc/fstab |awk '{print $2,$4}' /app defaults /boot defaults swap defaults [root@centos7 ~]# tail -3 /etc/fstab |awk '{print $2"\t"$4}' /appdefaults /bootdefaults swapdefaults
2、变量
2.1 内建命令
FS:输入字段分隔符,默认为空白字符
~]# awk -v FS=: '{print $1,FS,$3}' /etc/passwd ~]# awk -F":" '{print $1,$3}' /etc/passwd
OFS:输出字段分隔符,默认为空白字符
~]# awk -v FS=":" -v OFS=: '{print $1,$3,$7 }' /etc/passwd
RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效
~]# awk -v RS=''^C{print}' /etc/passwd
ORS:输出记录分隔符,输出时用指定符号代替换行符
~]#awk -v RS=' ' -v ORS=' ' ‘{print }’ /etc/passwd
ARGC:命令行参数的个数
~]# awk -F: ‘{print NF}’ /etc/fstab,引用内置变量不用$ ~]# awk -F: '{print $(NF-1)}' /etc/passwd
ARGV:数组,保存命令行给定的各参数
~]# [root@centos7 ~]# awk -F: '{print NF}' /etc/passwd 7 7 ~]# awk -F: '{print $(NF-1)}' /etc/passwd /root /bin
NF:字段数量
~]# ~]# awk '{print NR}' /etc/fstab ; awk END'{print NR}' /etc/fstab
NR:行号
~]# awk {print NR}' /etc/fstab /etc/fatab
FNR:个文件分别计数,行号
~]#awk {print FNR}' /etc/fstab /etc/fatab
FILENAME:当前文件名
~]# awk '{print FILENAME}' /etc/fstab /etc/fstab /etc/fstab
ARGC:命令行参数的个数
~
]# awk '{print ARGC}' /etc/fstab /etc/inittab ~]# awk 'BEGIN{print ARGC}' /etc/fstab /etc/inittab
ARGV:数组,保存的是命令行所给定的各参数
~]# awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/inittab awk ~]# awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/inittab /etc/fstab ~]# awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/inittab /etc/inittab ~]# awk 'BEGIN{print ARGV[3]}' /etc/fstab /etc/inittab #没有索引为空
2.2 自定义变量
选项位置定义:-v var=hello
在program中定义:awk ‘BEGIN{test=”hello”;print test}’
示例:
[root@centos7 ~]# awk -v test='hello gawk' '{print test}' /etc/fstab
hello gawk
hello gawk
hello gawk
root@centos7 ~]# awk -v test='hello gawk' 'BEGIN{print test}' /etc/fstab
hello gawk
[root@centos7 ~]# awk 'BEGIN{r=test="hello,gawk";print test}' /etc/fstab
hello,gawk
[root@centos7 ~]# awk -F: '{sex="male";print $1,sex,age;age=18}' /etc/passwd
root male
bin male 18
daemon male 18
[root@centos7 ~]# cat awk.txt #脚本实现awk输出
{print script,$1,$2}
[root@centos7 ~]# awk -F: -f awk.txt txt="awk" /etc/passwd #-f调用swk脚本
root x
bin x
3、 printf命令
格式化输出:printf “FORMAT”, item1, item2, ...
(1) 必须指定FORMAT
(2) 不会自动换行,需要显式给出换行控制符,\n
(3) FORMAT中需要分别为后面每个item指定格式符
print不需要指定,printf需要指定format
printf后面的字串需要使用双引号
字串定义后的内容需要使用”,”分隔,后面直接跟Item1,item2….
format用于指定后面的每个item的输出格式
printf语句不会自动打印换行符\n
格式符
%s: 显示字符串
%d,%i: 显示十进制整数
%e,%E: 科学计数法数值显示
%f: 显示为浮点数
%g,%G: 以科学数法或浮点形式显示数值
%c: 显示字符的ASCII码
%u: 无符号整数
%%: 显示%号自身,相当于转义
修饰符
N: 显示宽度
-: 左对齐(默认为右对齐)
+: 显示数值符号
示例:
[root@centos7 ~]# awk -F: '{printf"%s",$1}' /etc/passwd
rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodysystemd-networkdbuspolkitdabrtlibstoragemgmtrpccolordsaslauthrtkitchronyqemutssusbmuxdgeocluerpcusernfsnobodyradvdsetroubleshootpulsegdmgnome-initial-s
[root@centos7 ~]# awk -F: '{printf"%s\n",$1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
[root@centos7 ~]# awk -F: '{printf"%-20s %10d\n",$1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
[root@centos7 ~]# awk -F: '{printf"%-20.2s %10d\n",$1,$3}' /etc/passwd
ro 0
bi 1
da 2
[root@centos7 ~]# awk -F: '{print "username:%s\n",$1}' /etc/passwd
username:%s
root
username:%s
bin
[root@centos7 ~]# awk -F: '{printf "username:%s,UID:%d\n",$1,$3}' /etc/passwd
username:root,UID:0
username:bin,UID:1
username:daemon,UID:2
username:adm,UID:3
username:lp,UID:4
username:sync,UID:5
[root@centos7 ~]# awk -F: '{printf "username:%15s,UID:%d\n",$1,$3}' /etc/passwd
username: root,UID:0
username: bin,UID:1
username: daemon,UID:2 #%15s 右对齐
username: adm,UID:3
[root@centos7 ~]# awk -F: '{printf "username:%-15s,UID:%d\n",$1,$3}' /etc/passwd
username:root ,UID:0
username:bin ,UID:1
username:daemon ,UID:2 #%-15s 左对齐
username:adm ,UID:3
[root@centos7 ~]# awk -F: '{printf "username:%-20s salary:%-10.2f shell:%s\n",$1,$3,$7}' /etc/passwd
username:root salary:0.00 shell:/bin/bash
username:bin salary:1.00 shell:/sbin/nologin
username:daemon salary:2.00 shell:/sbin/nologin
username:adm salary:3.00 shell:/sbin/nologin
username:lp salary:4.00 shell:/sbin/nologin
username:sync salary:5.00 shell:/bin/sync
username:shutdown salary:6.00 shell:/sbin/shutdown
username:halt salary:7.00 shell:/sbin/halt
4、操作符
算数操作符
x+y, x-y, x*y, x/y, x^y, x%y
-x: 转换为负数 +x: 转换为数值
字符串操作符:没有符号的操作符,字符串连接
赋值操作符
=, +=, -=, *=, /=, %=, ^=,++, —
比较操作符
==, !=, >, >=, <, <=
模式匹配符
~:左边是否和右边匹配包含!~:是否不匹配
示例:
计算1加到100和为多少[root@centos7 ~]# echo {1..100}|tr " " + |bc
5050
[root@centos7 ~]# for ((sum=0,i=1;i<=100;i++));do let sum+=i;done;echo $sum
5050
[root@centos7 ~]# awk BEGIN'{for(i=1;i<=100;i++){sum+=i};print sum}'
5050
[root@centos7 ~]# awk BEGIN'{i=1;while (i<=100) {sum+=i;i++};print sum}'
5050
计算1加到100奇偶数和
#100以内偶奇数相加之和
[root@centos6 ~]# awk BEGIN'{sum=0;for(i=1;i<=100;i++){if(i%2==0){continue};sum+=i};print sum}'
2500
#100以内偶数相加之和
[root@centos6 ~]# awk BEGIN'{sum=0;for(i=1;i<=100;i++){if(i%2==1){continue};sum+=i};print sum}'
2550
#列出十以内的奇数
[root@centos6 ~]# seq 10 |awk '{if($1%2==0){next};print $1}'
1
3
5
7
9
#列出十以内的偶数
[root@centos6 ~]# seq 10 |awk '{if($1%2!=0){next};print $1}'
2
4
6
8
10
[root@centos7 ~]# awk -F: '$0 ~ /root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
root@centos7 ~]# awk -F: '$0 ~ /root/{print $1}' /etc/passwd
root
operator
[root@centos7 ~]# awk -F: '$0 ~ /^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@centos7 ~]# awk -F: '$0 !~ /root/' /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
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
.......
[root@centos7 ~]# awk -F: '$3==0' /etc/passwd
root:x:0:0:root:/root:/bin/bash
性能比较
[root@centos7 ~]# time(seq –s ”+” 1000000|bc) #bc运算
seq: invalid floating point argument: –s
Try 'seq --help' for more information.
real 0m0.004s
user 0m0.000s
sys 0m0.003s
[root@centos7 ~]# time(for ((i=0;i<=1000000;i++));do let total+=i;done;echo $total) #shell for运算
500000500000
real 0m7.236s
user 0m6.990s
sys 0m0.231s
[root@centos7 ~]#
[root@centos7 ~]# time(total=0;for i in {1..1000000};do total=$(($total+i));done;echo $total) #bash for运算
500000500000
real 0m7.150s
user 0m4.949s
sys 0m0.878s
[root@centos7 ~]# time (awk 'BEGIN{ total=0;for(i=0;i<=1000000;i++){total+=i;};print total;}') #awk运算
500000500000
real 0m0.217s
user 0m0.092s
sys 0m0.002s
逻辑操作符
与&&,或||,非! :
示例:
[root@centos7 ~]# awk -F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
root
bin
daemon
[root@centos7 ~]# awk -F: '$3==0 || $3<=1000 {print $1}' /etc/passwd
root
bin
daemon
[root@centos7 ~]# awk -F: '!($3==0) {print $1}' /etc/passwd
bin
daemon
adm
[root@centos7 ~]# awk -F: '($3>=1000) {print $3}' /etc/passwd
65534
1000
1001
1002
4444
[root@centos7 ~]# awk -F: '!($3>=1000) {print $1}' /etc/passwd
root
bin
daemon
adm
[root@centos7 ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd
nfsnobody 65534
li 1000
123 1001
12 1002
19 4444
函数调用: function_name(argu1, argu2, ...)
条件表达式(三目表达式):
selector?if-true-expression:if-false-expression
示例:
[
[root@centos7 ~]# awk -F: '{$3>=1000?UserType="Common User":UserType="Sysasmin or sysUser";printf "%15s: %s\n",$1,UserType}' /etc/passwd
root: Sysasmin or sysUser
bin: Sysasmin or sysUser
daemon: Sysasmin or sysUser
adm: Sysasmin or sysUser
lp: Sysasmin or sysUser
sync: Sysasmin or sysUser
shutdown: Sysasmin or sysUser
halt: Sysasmin or sysUser
mail: Sysasmin or sysUser
operator: Sysasmin or sysUser
games: Sysasmin or sysUser
ftp: Sysasmin or sysUser
nobody: Sysasmin or sysUser
systemd-network: Sysasmin or sysUser
dbus: Sysasmin or sysUser
polkitd: Sysasmin or sysUser
abrt: Sysasmin or sysUser
libstoragemgmt: Sysasmin or sysUser
rpc: Sysasmin or sysUser
colord: Sysasmin or sysUser
saslauth: Sysasmin or sysUser
rtkit: Sysasmin or sysUser
chrony: Sysasmin or sysUser
qemu: Sysasmin or sysUser
tss: Sysasmin or sysUser
usbmuxd: Sysasmin or sysUser
geoclue: Sysasmin or sysUser
rpcuser: Sysasmin or sysUser
nfsnobody: Common User
radvd: Sysasmin or sysUser
setroubleshoot: Sysasmin or sysUser
pulse: Sysasmin or sysUser
gdm: Sysasmin or sysUser
gnome-initial-setup: Sysasmin or sysUser
sshd: Sysasmin or sysUser
avahi: Sysasmin or sysUser
postfix: Sysasmin or sysUser
ntp: Sysasmin or sysUser
tcpdump: Sysasmin or sysUser
li: Common User
apache: Sysasmin or sysUser
123: Common User
12: Common User
19: Common User
5、PATTERN
PATTERN:根据pattern条件,过滤匹配的行,再做处理
(1)如果未指定:空模式,匹配每一行
(2) /regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来
awk '/^UUID/{print $1}' /etc/fstab 仅处理匹配到的行
awk '!/^UUID/{print $1}' /etc/fstab 仅处理匹配到的行
(3) relational expression: 关系表达式,结果有“真”有“假”;结果为“真”才会被处理 ;
真:结果为非0值,非空字符串
假:结果为空字符串或0值
(4) line ranges:行范围
startline,endline:/pat1/,/pat2/ 处理 pattern1 到 pattern2 之间
注意:不支持直接给出数字格式
(5) BEGIN/END模式
BEGIN{}: 仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
示例:
[root@centos7 ~]# df #处理前显示
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda2 20961280 3750180 17211100 18% /
devtmpfs 485144 0 485144 0% /dev
tmpfs 499848 0 499848 0% /dev/shm
tmpfs 499848 19832 480016 4% /run
tmpfs 499848 0 499848 0% /sys/fs/cgroup
/dev/sda5 20961280 32948 20928332 1% /app
/dev/sda1 201380 138984 62396 70% /boot
tmpfs 99972 36 99936 1% /run/user/0
/dev/sr0 8490330 8490330 0 100% /media
[root@centos7 ~]# df |grep /dev/sd |awk '{printf "DevName:%s Used:%s\n",$1,$5}'
#显示/dev/sd开头的行并对其输出显示进行优化
DevName:/dev/sda2 Used:18%
DevName:/dev/sda5 Used:1%
DevName:/dev/sda1 Used:70%
[root@centos7 ~]# df | awk '$0 ~ "/dev/sd" {printf "DevName:%-10s Used:%s\n",$1,$5}'
DevName:/dev/sda2 Used:18%
DevName:/dev/sda5 Used:1%
DevName:/dev/sda1 Used:70%
[root@centos7 ~]# df |awk '$1~"^/dev/sd[[:lower:]][[:digit:]]\\>" && $5>=10 {printf "Filesystem: %-15s Used: %s\n",$1,$5}'
Filesystem: /dev/sda2 Used: 18%
Filesystem: /dev/sda1 Used: 70%
[root@centos7 ~]# df |awk '/\/dev\/sd[[:lower:]][[:digit:]]\>/{if($5>10){printf "DevName:%-10s Used:%s\n",$1,$5}}'
DevName:/dev/sda2 Used:18%
DevName:/dev/sda1 Used:70%
[root@centos7 ~]# awk -F: '$3<1000{print $1,$3 }' /etc/passwd
root 0
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
abrt 173
libstoragemgmt 998
rpc 32
colord 997
saslauth 996
rtkit 172
chrony 995
qemu 107
tss 59
usbmuxd 113
geoclue 994
rpcuser 29
radvd 75
setroubleshoot 993
pulse 171
gdm 42
gnome-initial-setup 992
sshd 74
avahi 70
postfix 89
ntp 38
tcpdump 72
apache 48
[root@centos7 ~]# awk -F: '$NF=="/bin/bash"{print $1,NF }' /etc/passwd
#匹配最后一列为"/bin/bash",输出$1和列数NF的值
root 7
li 7
123 7
12 7
19 7
[root@centos7 ~]# awk -F: '$NF=="/bin/bash"{print $1,$NF }' /etc/passwd
#匹配最后一列为"/bin/bash",输出$1和$NF变量的值
root /bin/bash
li /bin/bash
123 /bin/bash
12 /bin/bash
19 /bin/bash
[root@centos7 ~]# awk -F: '$NF ~ "/bin/bash"{print $1,$NF }' /etc/passwd #
root /bin/bash
li /bin/bash
123 /bin/bash
12 /bin/bash
19 /bin/bash
[root@centos7 ~]# awk -F: '$NF ~ /bash$/{print $1,$NF }' /etc/passwd
root /bin/bash
li /bin/bash
123 /bin/bash
12 /bin/bash
19 /bin/bashm
[root@centos7 ~]# awk -F: '(NR<=28&&NR>=10){print $1}' /etc/passwd
operator
games
ftp
nobody
systemd-network
dbus
polkitd
abrt
libstoragemgmt
rpc
colord
saslauth
rtkit
chrony
qemu
tss
usbmuxd
geoclue
rpcuser
[root@centos7 ~]# awk '/UUID/{print $1}' /etc/fstab
UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b
[root@centos7 ~]# awk -F: '/^root\>/,/^ftp\>/{print $1}' /etc/passwd #root开头到ftp开头之间的行
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
[root@centos7 ~]# awk -F: 'BEGIN{print " USER USERID"}/^root\>/,/^ftp\>/{printf "%20s %s %-5s\n", $1,":",$3}END{print " end file"}' /etc/passwd
#BEGIN指定(修饰)第一个输出,/^root\>/,/^ftp\>指定(修饰)范围第二个输出,END指定(修饰)最后一个输出范围
USER USERID
root : 0
bin : 1
daemon : 2
adm : 3
lp : 4
sync : 5
shutdown : 6
halt : 7
mail : 8
operator : 11
games : 12
ftp : 14
end file
[root@centos7 ~]# awk -F: 'BEGIN{print "user uid \n------------------"}/^root\>/,/^ftp\>/{print $1,$3}' /etc/passwd
user uid
------------------
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
[root@centos7 ~]# awk -F: 'BEGIN{print "user uid \n------------------"}/^root\>/,/^ftp\>/{print $1,$3}END{print "==============="}' /etc/passwd
user uid
------------------
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
===============
6、常用的action
(1) Expressions:算术,比较表达式等
(2) Control statements:if, while等
(3) Compound statements:组合语句
(4) input statements
(5) output statements:print等
7控制语句
简述控制语句格式:
if(condition){statments}
if(condition){statments} else {statments}
while(condition){statments}
do {statements} while (condition)
for(expr1;expr2;expr3){statements}
break
continue
delete array [index]
delete array
exit
{statements}
7.1 if-else
语法:
if(condition){statments}
if(condition){statments} else {statments}
if(condition1){statement1}else if(condition2){statement2} else{statement3}
使用场景:对awk取得的整行或某个字段做条件判断
示例:
[root@centos7 ~]# awk 'BEGIN{ test=100;if(test>90){print "very good"}else if(test>60){ print "good"}else{print "no pass"}}'
very good
成绩为100;大于90打印“very good”;大于60打印“good”;其余打印“no pass”
[root@centos7 ~]# awk '{if($3>=1000){printf "Common user: %s\n",$1 } else{printf "root or sysuser : %s\n",$1}}' /etc/passwd
root or sysuser : root:x:0:0:root:/root:/bin/bash
root or sysuser : bin:x:1:1:bin:/bin:/sbin/nologin
root or sysuser : daemon:x:2:2:daemon:/sbin:/sbin/nologin
root or sysuser : adm:x:3:4:adm:/var/adm:/sbin/nologin
root or sysuser : lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
root or sysuser : sync:x:5:0:sync:/sbin:/bin/sync
root or sysuser : shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
root or sysuser : halt:x:7:0:halt:/sbin:/sbin/halt
root or sysuser : mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
root or sysuser : operator:x:11:0:operator:/root:/sbin/nologin
root or sysuser : games:x:12:100:games:/usr/games:/sbin/nologin
[root@centos7 ~]# awk -F: '{if($NF=="/bin/bash")print $1}' /etc/passwd
#NF字段数量,$NF表示最后字段的值,判断字段值等于/bin/bash
root
li
123
12
19
[root@centos7 ~]# awk '{if(NF>5)print $0}' /etc/passwd
#NF字段数量,判断字段数大于5的行
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
[root@centos7 ~]# awk '{if(NF>5)print $0}' /etc/fstab
# Created by anaconda on Tue Jan 9 05:14:54 2018
# 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
UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff / xfs defaults 0 0
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0
[root@centos7 ~]# df -h |awk -F% '{print $1}'
Filesystem Size Used Avail Use
/dev/sda2 20G 3.6G 17G 18
devtmpfs 474M 0 474M 0
tmpfs 489M 0 489M 0
tmpfs 489M 20M 469M 4
tmpfs 489M 0 489M 0
/dev/sda5 20G 33M 20G 1
/dev/sda1 197M 136M 61M 70
tmpfs 98M 36K 98M 1
/dev/sr0 8.1G 8.1G 0 100
[root@centos7 ~]# df -h |awk -F% '{print $1}'|awk '{print $NF}'
Use
18
0
0
4
0
1
70
1
100
[root@centos7 ~]# df -h |awk -F% '/^\/dev/{print $1}'|awk '{print $NF}'
18
1
70
100
#将/etc/passwd第一列当作姓名,第三列当作工资,打印报表,要求显示:
#Name:zhangsan Salary:3300 Level:High
#工资大于3000的,Level显示High,大于1000,小于等于3000的显示Soso,小于1000的显示LOW。
[root@centos7 ~]# awk -F: '{if($3>3000){Level="High"}else if($3>1000 && $3<=3000){Level="Soso"}else{Level="Low"};printf "Name:%-20s Salary:%-20d Level:%s\n",$1,$3,Level}' /etc/passwd
Name:root Salary:0 Level:Low
Name:bin Salary:1 Level:Low
Name:daemon Salary:2 Level:Low
Name:adm Salary:3 Level:Low
Name:lp Salary:4 Level:Low
Name:sync Salary:5 Level:Low
Name:shutdown Salary:6 Level:Low
Name:halt Salary:7 Level:Low
Name:mail Salary:8 Level:Low
Name:operator Salary:11 Level:Low
Name:games Salary:12 Level:Low
Name:ftp Salary:14 Level:Low
Name:nobody Salary:99 Level:Low
Name:systemd-network Salary:192 Level:Low
Name:dbus Salary:81 Level:Low
Name:polkitd Salary:999 Level:Low
Name:abrt Salary:173 Level:Low
Name:libstoragemgmt Salary:998 Level:Low
Name:rpc Salary:32 Level:Low
Name:colord Salary:997 Level:Low
Name:saslauth Salary:996 Level:Low
Name:rtkit Salary:172 Level:Low
Name:chrony Salary:995 Level:Low
Name:qemu Salary:107 Level:Low
Name:tss Salary:59 Level:Low
Name:usbmuxd Salary:113 Level:Low
Name:geoclue Salary:994 Level:Low
Name:rpcuser Salary:29 Level:Low
Name:nfsnobody Salary:65534 Level:High
Name:radvd Salary:75 Level:Low
Name:setroubleshoot Salary:993 Level:Low
Name:pulse Salary:171 Level:Low
Name:gdm Salary:42 Level:Low
Name:gnome-initial-setup Salary:992 Level:Low
Name:sshd Salary:74 Level:Low
Name:avahi Salary:70 Level:Low
Name:postfix Salary:89 Level:Low
Name:ntp Salary:38 Level:Low
Name:tcpdump Salary:72 Level:Low
Name:li Salary:1000 Level:Low
Name:apache Salary:48 Level:Low
Name:123 Salary:1001 Level:Soso
Name:12 Salary:1002 Level:Soso
Name:19 Salary:4444 Level:High
7.2 while循环
语法:while(condition){statments}
意义:条件”真”,进入循环;条件”假”,退出循环
使用场景:对于行内的多个字段逐一类似处理时使用,对数组中的个元素逐一处理时使用。
[root@centos7 ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $1,length($i);i++}}' /etc/grub2.cfg
linux16 7
linux16 30
linux16 46
linux16 2
linux16 4
linux16 5
linux16 16
linux16 7
linux16 50
linux16 46
linux16 2
linux16 4
linux16 5
[root@centos7 ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){if(length($i)>=40){print $1,length($i)};i++}}' /etc/grub2.cfg
#以空白符开头后跟”linux16″的行中,把字符数大于40的字符串打印出来。
linux16 46
linux16 50
linux16 46
7.3 do-while循环
语法:do {statements} while (condition)
(无论真假,至少执行一次循环体 )
示例:
[root@centos7 ~]# seq 3|awk 'BEGIN{i=1;print i++,i}'
#i的值:先输出i的值,在做(加法)运算
1 2
[root@centos7 ~]# seq 3|awk 'BEGIN{i=1;print ++i,i}'
#i的值:先做(加法)运算,在输出i 的值
2 2
[root@centos7 ~]# awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}'
#累加运算:计算0-100之和
5050
7.4 for循环
语法:for(expr1;expr2;expr3) {statement;…}
常见用法:for(variable assignment;condition;iteration process) {for-body}
特殊用法:
能够遍历数组中的元素
语法:for(var in array) {for-body}
示例:
[root@centos7 ~]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print$i,length($i)}}' /etc/grub2.cfg
#遍历:统计以linux16开头的行各字符串出现次数
linux16 7
/vmlinuz-3.10.0-693.el7.x86_64 30
root=UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff 46
ro 2
rhgb 4
quiet 5
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-ff4aa58d9e1f44f7b7aae5f6fd1a3242 50
root=UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff 46
ro 2
rhgb 4
quiet 5
7.5 switch语句
语法:switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}
7.6 break和continue
break [n]
continue [n]
awk ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}’
awk ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}’
7.7 net
提前结束对本行处理而直接进入下一行处理(awk自身循环)
示例:
[root@centos7 ~]# awk -F: '{if($3%2!=0) print $1,$3}' /etc/passwd
root 0
daemon 2
lp 4
shutdown 6
mail 8
games 12
ftp 14
systemd-network 192
libstoragemgmt 998
rpc 32
saslauth 996
rtkit 172
geoclue 994
nfsnobody 65534
gdm 42
gnome-initial-setup 992
sshd 74
avahi 70
ntp 38
tcpdump 72
li 1000
apache 48
12 1002
[root@centos7 ~]# seq 20 | awk -F: '{if($1%2==0)next ; print $1}'
#打印奇数行;匹配$1%2取余数的等于0的结束循环
1
3
5
7
9
11
13
15
17
19
8、array(数组 )
关联数组:array[index-expression]
index-expression:
(1) 可使用任意字符串;字符串要使用双引号括起来
(2) 如果某数组元素事先不存在,在引用时,awk会自动创建 此元素,并将其值初始化为“空串”
若要判断数组中是否存在某元素,要使用“index in array”格 式进行遍历
若要遍历数组中的每个元素,要使用for循环;
for(var in array) {for-body}
注意:var会遍历array的每个索引;
state["LISTEN"]++
state["ESTABLISHED"]++
9、函数
数值处理:
rand():返回0和1之间一个随机数
[root@centos7 ~]# awk 'BEGIN{srand();print int(rand()*100)}'
#随机一个两位数的整数,*100
71
字符串处理:
length([s]):返回指定字符串的长度
sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹 配的内容替换为s
[root@nanyibo ~]# echo "2018:3:30 17:38:30" |awk 'sub(/:/,"-",$1)'
2018-3:30 17:38:30
gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换 为s所表示的内容
[root@nanyibo ~]# echo "2018:3:30 17:38:30" |awk 'gsub(/:/,"-",$1)'
2018-3-30 17:38:30
split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存 至array所表示的数组中,第一个索引值为1,第二个索引值为2,…
netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++} END{for (i in count) {print i,count[i]}}'
#先进行分割,取出第五列对第五列做分割取出以分隔符:的第一列,设置变量count索引为ip[1]做加法运算,只输出一次结果。
自定义函数
格式:
function name ( parameter, parameter, ... ) {
statements
return expression
}
示例:
#cat fun.awk function max(
v1,v2) { v1>v2?var=v1:var=v2
return var
}
BEGIN{a=3;b=2;print max(a,b)}
#awk –f fun.awk
示例:
[root@nana ~]# cat fi.txt
1 2 3 4 5 6 7 8 9 10
11 12 12 14 15 16 17 18 19 20
[root@nana ~]# awk '{i=1;sum=0;while(i<=NF){sum+=$i;i++};print sum}' f1.txt 显示每行各自的总行
55
155
[root@nana ~]# awk '{i=1;while(i<=NF){sum+=$i;i++};print sum}' f1.txt 每行显示一次总和
55
210
[root@nana ~]# awk '{i=1;while(i<=NF){sum+=$i;i++}}END{print sum}' f1.txt 只显示总和
210
对十以内整数奇数输出jishu,偶数输出偶数
效果如下:
1 jishu
2 oushu
3 jishu
[root@centos7 /]# echo {1..10} |awk '{i=1;while(i<=NF){if($i%2==0){print $i,"is oushu"} else{print $i, "is jishu"};i++}}'
1 is jishu
2 is oushu
3 is jishu
4 is oushu
5 is jishu
6 is oushu
7 is jishu
8 is oushu
9 is jishu
10 is oushu
[root@centos7 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}'
Tuesday
Monday
[root@centos7 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i] ,i}}'
#i的值为每次数组weekdays的索引,这个过程称为遍历
Tuesday tue
Monday mon
函数统计类型出现次数
~]# netstat -tan |awk '/^tcp\>/{state[$NF]++}END{for (i in state){ print i,state[i]}}'
#函数state中下标为$NF的值:LISTEN和ESTABLISHED,他们的值做++运算,
#END{}:仅在文本完成之后执行一次,后边for循环只做一次,
#i变量的值为:数组state的下标,也就是:LISTEN和ESTABLISHED。
#print i的值为for训话i的值,就是$NF的值:LISTEN和ESTABLISHED。
#state[i]的值为,END前边完成时的值++的相加之和,
#也就是state数组的值:state[LISTEN]=3和state[ESTABLISHED]=1
LISTEN 8
ESTABLISHED 3
显示/bash类型次数
[root@centos7 ~]# awk -F: '{shell[$7]++}END{for(n in shell){print n,shell[n]}}' /etc/passwd
/bin/sync 1
/bin/bash 5
/sbin/nologin 36
/sbin/halt 1
/sbin/shutdown 1
统计http日志文件,IP地址访问次数
[root@centos7 ~]# awk '{ip[$1]++}END{for(i in ip){print i ,ip[i]}}' /var/log/httpd/access_log
172.18.253.55 1788
172.18.251.122 52
172.18.251.150 34
172.18.251.141 30
172.18.251.160 157
172.18.251.170 457
172.18.251.107 14
172.18.251.109 51
172.18.251.145 50
172.18.0.223 12
172.18.253.21 74087
::1 15
172.18.251.147 354
172.18.254.78 183
172.18.251.157 330
172.18.252.134 514
172.18.251.149 158
172.18.254.6 1643
172.18.250.183 81
172.18.251.21 81
172.18.254.34 659
awk实现取出从定向
[root@centos7 ~]# awk -F: '! shell[$7]++' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/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
去重
[root@centos6 ~]#awk -F: '!shell[$0]++' /etc/passwd #去重
统计/etc/fstab文件中每个文件系统类型出现的次数;
#源文件
[root@centos7 ~]# awk '/^UUID/{print $0}' /etc/fstab
UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff / xfs defaults 0 0
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0
[root@centos7 ~]# awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab
swap 1
xfs 3
统计指定文件中每个单词出现的次数;
[root@centos7 ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b 1
Tue 1
man 1
and/or 1
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e 1
maintained 1
xfs 3
Accessible 1
# 7
are 1
defaults 4
Jan 1
blkid(8) 1
/ 1
0 8
See 1
Created 1
05:14:54 1
on 1
mount(8) 1
9 1
anaconda 1
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c 1
fstab(5), 1
/app 1
/boot 1
findfs(8), 1
2018 1
'/dev/disk' 1
by 2
/etc/fstab 1
pages 1
more 1
info 1
swap 2
filesystems, 1
reference, 1
UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff 1
for 1
under 1
脚本实现AWK
system命令
空格是awk中的字符串连接符,如果system中需要使用awk中 的变量可以使用空格分隔,或者说除了awk的变量外其他一律 用""引用起来。
awk BEGIN'{system("hostname") }' awk 'BEGIN{score=100; system("echo your score is " score) }'
[root@nanyibo ~]# cat awk.txt
function max(v1,v2){
v1>v2?var=v1:var=v2
return var
}
BEGIN{print max(a,b)}
[root@nanyibo ~]# awk -v a=30 -v b=20 -f awk.txt
30
[root@nanyibo ~]# awk -v a=10 -v b=20 -f awk.txt
20
将awk程序写成脚本,直接调用或执行
示例:
#cat f1.awk
{if($3>=1000)print $1,$3}
#awk -F: -f f1.awk /etc/passwd
#cat f2.awk
#!/bin/awk –f
#this is a awk script
{if($3>=1000)print $1,$3}
#chmod +x f2.awk
#f2.awk –F: /etc/passwd
向awk脚本传递参
格式:
awkfile var=value var2=value2... Inputfile
注意:在BEGIN过程中不可用。直到首行输入完成以后,变 量才可用。可以通过-v 参数,让awk在执行BEGIN之前得到 变量的值。命令行中每一个指定的变量都需要一个-v参数
示例:
#cat test.awk
#!/bin/awk –f
{if($3 >=min && $3<=max)print $1,$3}
#chmod +x test.awk
#test.awk -F: min=100 max=200 /etc/passwd