简介
awk 报告生成器,作用格式化文本输出:
awk分为awk.nawk. gawk。
但是linux上的awk为gawk
[root@web1 base]# which awk /usr/bin/awk [root@web1 base]# ll /usr/bin/awk lrwxrwxrwx. 1 root root 4 Jul 26 10:57 /usr/bin/awk -> gawk
基本用法
gawk [options] 'program' FILE ...
program: PATTERN{ACTION STATEMENTS}
可以允许多个语句,语句之间用分号分隔
选项
-F: 指明输入时用到的字段分隔符;
-v var=value: 自定义变量
工作模式
一行一行读取,默认按空格分隔,默认保存在awk的内建变量中。$0显示所有 $1显示第一个 以此类推。
输出命令
1. print
print item1,item2
要点:
(1) 逗号分割符‘
(2)输出的个item可以是字符串,也可以是数值(运算是依旧是数值,但是输出后为字符串。);当前记录的字段、变量活awk的表达式;
(3)如省略item,相当于print $0;
2. 变量
(1)内建变量
FS: input field separator(输入字段分隔符) 默认为空白字符
[root@web1 script]# awk -v FS=':' '{print $1}' /etc/passwd root bin daemon adm lp sync shutdown halt mail operator games ftp nobody systemd-network dbus polkitd postfix sshd
OFS: output field separator(输出字段分割符)默认为空白字符
[root@web1 script]# awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd root:0:/bin/bash bin:1:/sbin/nologin daemon:2:/sbin/nologin adm:3:/sbin/nologin lp:4:/sbin/nologin sync:5:/bin/sync shutdown:6:/sbin/shutdown halt:7:/sbin/halt mail:8:/sbin/nologin operator:11:/sbin/nologin games:12:/sbin/nologin ftp:14:/sbin/nologin nobody:99:/sbin/nologin systemd-network:192:/sbin/nologin dbus:81:/sbin/nologin polkitd:999:/sbin/nologin postfix:89:/sbin/nologin sshd:74:/sbin/nologin
RS:input record separator,输入时的换行符;
[root@web1 script]# awk -v RS=' ' '{print}' /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 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 operator:x:11:0:operator:/root:/sbin/nologin games:x:12:100:games:/usr/games:/sbin/nologin ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin nobody:x:99:99:Nobody:/:/sbin/nologin systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin dbus:x:81:81:System message bus:/:/sbin/nologin polkitd:x:999:997:User for polkitd:/:/sbin/nologin postfix:x:89:89::/var/spool/postfix:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin 原来的换行符还是换行符
ORS output record separator,输出的换行符;
[root@web1 script]# awk -v ORS=' ' '{print}' /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 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 operator:x:11:0:operator:/root:/sbin/nologin games:x:12:100:games:/usr/games:/sbin/nologin ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin nobody:x:99:99:Nobody:/:/sbin/nologin systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin dbus:x:81:81:System message bus:/:/sbin/nologin polkitd:x:999:997:User for polkitd:/:/sbin/nologin postfix:x:89:89::/var/spool/postfix:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin [root@web1 script]#
NF:number of filed 字段数量
在awk内部引用变量不需要加$ 引用字段需要加行数。
[root@web1 script]# awk '{print NF}' /etc/passwd 1 1 1 1 1 1 1 1 1 1 1 2 1 3 3 3 1 2 [root@web1 script]# awk '{print $NF}' /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 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 operator:x:11:0:operator:/root:/sbin/nologin games:x:12:100:games:/usr/games:/sbin/nologin User:/var/ftp:/sbin/nologin nobody:x:99:99:Nobody:/:/sbin/nologin Management:/:/sbin/nologin bus:/:/sbin/nologin polkitd:/:/sbin/nologin postfix:x:89:89::/var/spool/postfix:/sbin/nologin SSH:/var/empty/sshd:/sbin/nologin
NR: number of record, 行数
[root@web1 script]# awk '{print NR}' /etc/passwd 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
如果多个文件进行计数,会和起来显示
[root@web1 script]# awk '{print NR}' /etc/passwd /etc/issue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
FNR: 每一个文件进行单个计行数;
[root@web1 script]# awk '{print FNR}' /etc/passwd /etc/issue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1 2 3
FILENAME: 当前正在处理文件名字
[root@web1 script]# awk '{print FILENAME}' /etc/passwd /etc/issue /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/passwd /etc/issue /etc/issue /etc/issue
ARGC:命令行参数的个数:
[root@web1 script]# awk '{print ARGC}' /etc/passwd /etc/issue 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 [root@web1 script]# awk 'BEGIN{print ARGC}' /etc/passwd /etc/issue 3
ARGV: 数组,保存的是命令行所给定的各参数。
[root@web1 script]# awk 'BEGIN{print ARGC}' /etc/passwd /etc/issue 3 [root@web1 script]# awk 'BEGIN{print ARGV[0]}' /etc/passwd /etc/issue awk [root@web1 script]# awk 'BEGIN{print ARGV[1]}' /etc/passwd /etc/issue /etc/passwd [root@web1 script]# awk 'BEGIN{print ARGV[2]}' /etc/passwd /etc/issue /etc/issue
(2)自定义变量
1. -v var=value
变量名区分字符大小写;
[root@web1 script]# awk -v test='hello' '{print test}' /etc/fstab hello hello hello hello hello hello hello hello hello hello [root@web1 script]# awk -v test='hello' 'BEGIN{print test}' hello
2. program 定义
[root@web1 script]# awk 'BEGIN{test="hello hai";print test}' hello hai
3.printf命令
格式化输出: printf FORMAT,ITEM1.ITEM2,.....
(1)FORMAT必须给出;
(2)不会自动换行,需要显式给出换行控制符,
(3)FORMAT中需要分别为后面的每个item指定一个格式化符号;
格式符:
%c: 显示字符的ASCII码
%d,%i::显示十进制整数;
%e,%E: 科学计数法数值显示
%f: 显示为浮点数;
%g,%G: 以科学技术法或浮点形势显示数值;
%s: 显示字符串;
%u: 无符号整数;
%%: 显示%自身
[root@web1 script]# awk -F: '{printf "username: %s ",$1}' /etc/passwd username: root username: bin username: daemon username: adm username: lp username: sync username: shutdown username: halt username: mail username: operator username: games username: ftp username: nobody username: systemd-network username: dbus username: polkitd username: postfix username: sshd
[root@web1 script]# awk -F: '{printf "username: %s,UID: %d ",$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 username: shutdown,UID: 6 username: halt,UID: 7 username: mail,UID: 8 username: operator,UID: 11 username: games,UID: 12 username: ftp,UID: 14 username: nobody,UID: 99 username: systemd-network,UID: 192 username: dbus,UID: 81 username: polkitd,UID: 999 username: postfix,UID: 89 username: sshd,UID: 74
修饰符:
#[.#]:第一个数字控制显示的快读;第二个表示小数点后的精度:
如 %3.1f
[root@web1 script]# awk -F: '{printf "username: %15s,UID: %d ",$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 username: shutdown,UID: 6 username: halt,UID: 7 username: mail,UID: 8 username: operator,UID: 11 username: games,UID: 12 username: ftp,UID: 14 username: nobody,UID: 99 username: systemd-network,UID: 192 username: dbus,UID: 81 username: polkitd,UID: 999 username: postfix,UID: 89 username: sshd,UID: 74
-: 左对齐
[root@web1 script]# awk -F: '{printf "username: %-15s,UID: %d ",$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 username: shutdown ,UID: 6 username: halt ,UID: 7 username: mail ,UID: 8 username: operator ,UID: 11 username: games ,UID: 12 username: ftp ,UID: 14 username: nobody ,UID: 99 username: systemd-network,UID: 192 username: dbus ,UID: 81 username: polkitd ,UID: 999 username: postfix ,UID: 89 username: sshd ,UID: 74
+:显示数值的服务 加号会显示出来
[root@web1 script]# awk -F: '{printf "username: %-15s,UID: %+d ",$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 username: shutdown ,UID: +6 username: halt ,UID: +7 username: mail ,UID: +8 username: operator ,UID: +11 username: games ,UID: +12 username: ftp ,UID: +14 username: nobody ,UID: +99 username: systemd-network,UID: +192 username: dbus ,UID: +81 username: polkitd ,UID: +999 username: postfix ,UID: +89 username: sshd ,UID: +74
4.操作符
算数操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x
+x: 转化为数值
字符串操作符: 没有符号的操作符, 字符串连接
赋值操作符:
=, +=, -=, 、=, %=, ……=
++, --
比较操作符:
>,>=,<,<=,!=,==
模式匹配符:
~: 是否匹配
!~ 是否不匹配
逻辑操作符:
&&
||
!
函数调用:
function_name(argu1,argu2,...)
条件表达式:
selector?if-true-expression:if-false-expression
[root@web1 script]# awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf "%-15s:%s ",$1,usertype}' /etc/passwd root :Sysadmin or SysUser bin :Sysadmin or SysUser daemon :Sysadmin or SysUser adm :Sysadmin or SysUser lp :Sysadmin or SysUser sync :Sysadmin or SysUser shutdown :Sysadmin or SysUser halt :Sysadmin or SysUser mail :Sysadmin or SysUser operator :Sysadmin or SysUser games :Sysadmin or SysUser ftp :Sysadmin or SysUser nobody :Sysadmin or SysUser systemd-network:Sysadmin or SysUser dbus :Sysadmin or SysUser polkitd :Sysadmin or SysUser postfix :Sysadmin or SysUser sshd :Sysadmin or SysUser
5.PATTERN
(1) empty: 空模式,匹配每一行;
(2)/regular expression/: 仅处理能够被此处的模式匹配到的行
[root@web1 script]# awk '/^UUID/{print $1}' /etc/fstab UUID=0b8ca594-564a-47af-9e39-4a792e404379 UUID=eb2eed65-bb35-4af0-b08a-a816d8f13204
(3) relational expression: 关系表达式:结果又“真”有“假”;结果为“真”才会被处理
真: 结果为非0值,非空字符串表示为真;
[root@web1 script]# awk -F: '$3>=500{print $1,$3}' /etc/passwd polkitd 999
(4) line ranges: 行范围,
startline,endline: /pat1/,/pat2/
注意: 不支持直接给出数字的格式
[root@YJSJ-SERVER-02 application]# awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd bin daemon adm lp sync shutdown halt mail uucp
(5)BEGIN/END模式
BEGIN{}: 仅在开始处理文件的文本之前执行一次;
END{}: 仅在文本处理完成之后执行一次;
[root@YJSJ-SERVER-02 application]# awk -F: 'BEGIN{print "username uid ------------------"}{print $1,$3}' /etc/passwd username uid ------------------ root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 halt 7 mail 8 uucp 10 operator 11 games 12 gopher 13 ftp 14 nobody 99 vcsa 69 saslauth 499 postfix 89 sshd 74 ntp 38 tcpdump 72 nscd 28 nginx 500 zabbix 498 mysql 27 apache 48 squid 23 web 501 gitlab-www 497 git 496 gitlab-redis 495 gitlab-psql 494 gitlab-prometheus 493 dbus 81 nexus 502 jira 503 log 504 [root@YJSJ-SERVER-02 application]# awk -F: '{print "username uid ------------------"}{print $1,$3}' /etc/passwd username uid ------------------ root 0 username uid ------------------ bin 1 username uid ------------------ daemon 2 username uid ------------------ adm 3 username uid ------------------ lp 4 username uid ------------------ sync 5 username uid ------------------ shutdown 6 username uid ------------------ halt 7 username uid ------------------ mail 8 username uid ------------------ uucp 10 username uid ------------------ operator 11 username uid ------------------ games 12 username uid ------------------ gopher 13 username uid ------------------ ftp 14 username uid ------------------ nobody 99 username uid ------------------ vcsa 69 username uid ------------------ saslauth 499 username uid ------------------ postfix 89 username uid ------------------ sshd 74 username uid ------------------ ntp 38 username uid ------------------ tcpdump 72 username uid ------------------ nscd 28 username uid ------------------ nginx 500 username uid ------------------ zabbix 498 username uid ------------------ mysql 27 username uid ------------------ apache 48 username uid ------------------ squid 23 username uid ------------------ web 501 username uid ------------------ gitlab-www 497 username uid ------------------ git 496 username uid ------------------ gitlab-redis 495 username uid ------------------ gitlab-psql 494 username uid ------------------ gitlab-prometheus 493 username uid ------------------ dbus 81 username uid ------------------ nexus 502 username uid ------------------ jira 503 username uid ------------------ log 504
6.常用的action
(1)Expreessions 表达式
(2)Control statements: if,while等
(3)Compound statements: 组合语句
(4)input statements
(5)output statements
7.控制语句
if(condition){statements}
if(condition){statements} else {statement}
while(conditon){staements}
do {statement} while(conditon)
for(expr1,expr2,expr3){statements}
break
continue
delete array[index] 从数组中删除某个元素
delete arrat 删除数组
exit
{ statements}
7.1 if-else
语法: if(condition){statements} else {statement}
使用场景:对awk取的整行或某个字段做条件判断;
[root@web1 tmp]# awk -F: '{if($3>500) print$1,$3}' /etc/passwd polkitd 999
[root@web1 tmp]# awk -F: '{if($3>500) {printf "Conmon user: %s ",$1} else {printf "root or sysuser: %s ",$1}}' /etc/passwd root or sysuser: root root or sysuser: bin root or sysuser: daemon root or sysuser: adm root or sysuser: lp root or sysuser: sync root or sysuser: shutdown root or sysuser: halt root or sysuser: mail root or sysuser: operator root or sysuser: games root or sysuser: ftp root or sysuser: nobody root or sysuser: systemd-network root or sysuser: dbus Conmon user: polkitd root or sysuser: postfix root or sysuser: sshd
[root@web1 tmp]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd root [root@web1 tmp]# awk '{if(NF>5) print $0}' /etc/fstab # Created by anaconda on Thu Jul 26 10:57:01 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=0b8ca594-564a-47af-9e39-4a792e404379 / xfs defaults 0 0 UUID=eb2eed65-bb35-4af0-b08a-a816d8f13204 /boot xfs defaults 0 0
7.2 while循环
while(conditon){staements}
使用场景:对一行内的多个字段逐一类似处理时使用;
[root@web1 ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)}; i++}}' /etc/grub2.cfg linux16 7 /vmlinuz-3.10.0-693.el7.x86_64 30 root=UUID=0b8ca594-564a-47af-9e39-4a792e404379 46 crashkernel=auto 16 LANG=en_US.UTF-8 16 linux16 7 /vmlinuz-0-rescue-4448785178734432b18eb960343dfaae 50 root=UUID=0b8ca594-564a-47af-9e39-4a792e404379 46 crashkernel=auto 16
7.3 do-while
语法 :do {statement} while(conditon)
意义:只要执行一次循环体
7.4 for 循环
语法 for(expr1,expr2,expr3){statements}
for(variable assignment;codition iteration process)
[root@web1 ~]# awk '/^[[:space:]]*linux16/{for (i=1;i<NF;i++){print $i,length($i)}}' /etc/grub2.cfg linux16 7 /vmlinuz-3.10.0-693.el7.x86_64 30 root=UUID=0b8ca594-564a-47af-9e39-4a792e404379 46 ro 2 crashkernel=auto 16 rhgb 4 quiet 5 linux16 7 /vmlinuz-0-rescue-4448785178734432b18eb960343dfaae 50 root=UUID=0b8ca594-564a-47af-9e39-4a792e404379 46 ro 2 crashkernel=auto 16 rhgb 4 [root@web1 ~]# awk '/^[[:space:]]*linux16/{print}' /etc/grub2.cfg linux16 /vmlinuz-3.10.0-693.el7.x86_64 root=UUID=0b8ca594-564a-47af-9e39-4a792e404379 ro crashkernel=auto rhgb quiet LANG=en_US.UTF-8 linux16 /vmlinuz-0-rescue-4448785178734432b18eb960343dfaae root=UUID=0b8ca594-564a-47af-9e39-4a792e404379 ro crashkernel=auto rhgb quiet [root@web1 ~]#
特殊用法;
能够遍历数组中的元素;
语法: for(var in array)(for-body)
7.5 switch语句 多重判断语句
语句: switch(expression){case VALUE1 or /REGEXP/:statement; case VALUE2 or /REGEXP2/:statement;...default:statement}
7.6 break和continue
break [n]
continue
7.7 next
提前结束对本行的处理而直接进入下一行;
用户id为偶数的打印出来
[root@web1 ~]# 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 systemd-network 192 sshd 74
8.array
关联数组: ararry[index-expression]
index-expression
(1)可使用任意字符串;字符串要使用双引号;
(2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”;
若要判断数组中是否存在某元素,要使用“index in array”
[root@web1 tmp]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}' Monday [root@web1 tmp]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["tue"]}' Tuesday
若要遍历数组中的每个元素,要使用for循环;
for(var in array ){for-body}
[root@web1 tmp]# awk 'BEGIN{weekdays[1]="Monday";weekdays[2]="Tuesday";for(i in weekdays){print weekdays[i]}}' Monday Tuesday
注意:var会遍历array的每个索引;
[root@web1 tmp]# netstat -tan|awk '/^tcp>/{state[$NF]++}END{for(i in state){print i,state[i]}}' LISTEN 4 ESTABLISHED 8
'牟定符'
'< 词首牟定'
'> 词尾牟定'
' 放在词首则表示为牟定词首,放在词尾则表示为牟定词尾'
[root@YUE_TEST_02 application]# awk '{ip[$1]++}END{for( i in ip){print i,ip[i]} }' /var/log/nginx/access.log 91.106.77.208 1 80.82.70.187 1 152.231.52.173 1 78.211.208.37 1 37.195.147.56 1
显示每个单词出现的次数
[root@YUE_TEST_02 application]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for (i in count){print i,count[i]}}' /etc/fstab
9. 函数
9.1 内置函数
数值处理:
'rand(): 返回0和1一个随机数;'
[root@YUE_TEST_02 application]# awk 'BEGIN{print rand()}' 0.237788 [root@YUE_TEST_02 application]# awk 'BEGIN{print rand()}' 0.237788
awk命令只有第一次取到的是随机的
字符串处理
<!-- length([s]): 返回指定字符串的长度'
sub(r,s,[t]): 以r表示的模式来查找t所表示的字符串中的的匹配的内容,并将第一次出现替换为s所表示的内容;
gsub(r,s,[t]): 以r表示的模式来查找t所表示的字符串中的的匹配的内容,并将所有出现替换为s所表示的内容;
split(s,a,[r]) 以r为分割符切割字符s,并将切割后的结果保存至a所表示的数组中;
-->awk 数组以1未开始
[root@YJSJ-SERVER-02 ~]# netstat -tan |awk '/^tcp>/{split($5,ip,":");count[ip[1]]++}END{for(i in count ){print i,count[i] }}' 10.1.1.103 11 104.152.52.23 1 118.178.213.220 1 106.37.97.167 3 106.11.248.209 1 127.0.0.1 124 106.11.68.13 1 114.242.248.49 2 100.100.30.25 1 140.207.69.101 8 47.52.111.155 4 140.207.69.102 9 47.92.165.213 1 10.1.1.184 37 10.1.1.101 2 0.0.0.0 74 10.1.1.201 1 47.92.73.73 1 10.1.1.187 8 10.1.1.102 223