AWK

一、awk简介

awk是由3个人开发的:Aho, Weinberger, Kernighan;该功能主要是用来生成报告和格式化文本输出。它有多个版本:New awk(nawk),GNU awk( gawk)。我们通常在linux上使用的awk是基于GNU的awk。awk不只是一个命令,其真实,为一门语言,循环、数组、条件判断样样功能都有,功能非常强大,当然功能强大了,那么必定复杂。

二、基本用法:

awk [options] ‘program’ var=value file…
awk [options] ‘BEGIN{ action;… } pattern{ action;… } END{action;… }’ file …
awk [options] -f ‘a program file’ file …  (读取一个存有awk规则预存文件,再对指定文件进行处理)   这种用法,最后再说

options:

-F 指明输入时用到的字段分隔符(awk默认的分隔符就是空白字符)
-v var=value: 自定义变量   (awk的变量也分内置变量和自定义变量两种)

内置变量:

FS:输入字段分隔符,默认为空白字符
OFS:输出字段分隔符,默认为空白字符
RS:输入记录分隔符,指定输入时的换行符
ORS:输出记录分隔符,输出时用指定符号代替换行符
NF:字段数量
NR:记录号
FNR:各文件分别计数,记录号
FILENAME:当前文件名
ARGC:命令行参数的个数
ARGV:数组,保存的是命令行所给定的各参数

注意:虽然为内置变量,但是内置变量也可以用-v来声明初始值

1、awk [options] ‘program’ var=value file…用法的详细说明

program: pattern{action statements;..} #program由pattern和action两部分来组成

pattern和action:

• pattern部分决定动作语句何时触发及触发事件(也可以理解为匹配,用来过滤记录的)BEGIN,END
• action statements对数据进行处理,放在{}内指明print, printf

分割符、域和记录:

• awk执行时,由分隔符分隔的字段(域)标记$1,$2..$n称为域标识。$0为所有域,注意:和shell中变量$符含义不同
• 文件的每一行称为记录(一般的一行被称作一条记录)
• 省略action,则默认执行 print $0 的操作($0表示一整条记录,print表示打印输出的意思)

实例1,显示源输出的指定列:

  1. [root@newhostname /]# df | grep /dev/sd #先查看一下源标准输出
  2. /dev/sda1 1038336 162080 876256 16% /boot
  3. /dev/sdb3 3135488 135364 3000124 5% /mnt/xfs
  4. /dev/sdb2 3030800 9236 2847896 1% /mnt/ext4
  5. [root@newhostname /]# df | grep /sd | awk '{print $1"==="$5}'
  6. /dev/sda1===16%
  7. /dev/sdb3===5%
  8. /dev/sdb2===1%
  9. #$1为输出的第一列,$5为第5列,awk的默认字符是空表字符, 两列中间的等号为加入的字符串“===”

 实例2,使用awk的内置变量:

  1. [root@newhostname /]# awk -v FS=':' '{print $1,FS,$3}' /etc/passwd | head -5 #我们使用内置变量FS来作为分隔符
  2. root : 0
  3. bin : 1
  4. daemon : 2
  5. adm : 3
  6. lp : 4
  7. [root@newhostname /]# awk -F: '{print $1,FS,$3}' /etc/passwd | head -5 #我们使用-F option来指定分隔符
  8. root : 0
  9. bin : 1
  10. daemon : 2
  11. adm : 3
  12. lp : 4
  13. #由上面两个结果来看,其意义是一样的, 可以使用 -v 直接声明字段的分隔符,也可以用-F来指定。而在action内,变量是可以直接被调用的 ,注意,action内不要看走眼,如果是字符串的话,需要加“”“,直接输入的字符会当做变量来处理。

OFS变量的作用:

  1. [root@newhostname /]# awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd | head -5 #OFS输出字段分隔符,默认为空白,这里我们指定为“:”
  2. root:0:/bin/bash
  3. bin:1:/sbin/nologin
  4. daemon:2:/sbin/nologin
  5. adm:3:/sbin/nologin
  6. lp:4:/sbin/nologin
  7. [root@newhostname /]# awk -v FS=':' '{print $1,$3,$7}' /etc/passwd | head -5 #我们不指定OFS两段命令一对比,很明显,下面输出的使用的默认输出分隔符为空白。
  8. root 0 /bin/bash
  9. bin 1 /sbin/nologin
  10. daemon 2 /sbin/nologin
  11. adm 3 /sbin/nologin
  12. lp 4 /sbin/nologin

RS、ORS变量的应用:

  1. [root@newhostname zsfile]# cat 123.txt #文件的原输出
  2. dddd:112233:1000:1000 /home/bash:/bin/bash
  3. [root@newhostname zsfile]# awk -v RS=':' '{print }' ./123.txt #定义RS变更记录分隔符(默认的分隔符是换行符)
  4. dddd
  5. 112233
  6. 1000
  7. 1000 /home/bash
  8. /bin/bash
  9. [root@newhostname zsfile]# awk -v RS=':' -v ORS='|-|' '{print }' ./123.txt #我们定义ORS来改变输出的分隔符
  10. dddd|-|112233|-|1000|-|1000 /home/bash|-|/bin/bash
  11. |-|[root@newhostname zsfile]#

RS的意义是改变处理文本之前的记录分隔符,当处理完记录之后,输出记录分隔符(ORS)如果未定义,则还是现实原来默认的记录分隔符去显示,即默认的换行符。

实例3,NF字段数量,NR行号变量,FNR分文件行号变量,FILENAME当前的文件名,ARGC命令行参数的个数

  1. [root@newhostname zsfile]# vim 1111
  2. [root@newhostname zsfile]# cat 1111
  3. aa bb cc dd ee
  4. 11 22 33 44 55
  5. 33 22 11 ss 44
  6. [root@newhostname zsfile]# awk '{print NR,NF}' 1111 #NR表示第几行,NF为列的总数
  7. 1 5
  8. 2 5
  9. 3 5
  10. [root@newhostname zsfile]# awk '{print NR,$NF}' 1111 #$NF表示最后一列
  11. 1 ee
  12. 2 55
  13. 3 44
  14. [root@newhostname zsfile]# awk '{print NR,$NF}' 1111 123.txt #如果使用awk同时对多个文件进行处理,那么使用NR,最后的出列结果会合并成1个,而不会按文件分开,如果要按文件分开,要是用FNR
  15. 1 ee
  16. 2 55
  17. 3 44
  18. 4 /home/bash:/bin/bash
  19. [root@newhostname zsfile]# awk '{print FNR,$NF}' 1111 123.txt #使用FNR按文件分开
  20. 1 ee
  21. 2 55
  22. 3 44
  23. 1 /home/bash:/bin/bash
  24. [root@newhostname zsfile]# awk '{print FILENAME,FNR,$NF}' 1111 123.txt #FILENAME 在输出列输出文件的名字
  25. 1111 1 ee
  26. 1111 2 55
  27. 1111 3 44
  28. 123.txt 1 /home/bash:/bin/bash
  29. [root@newhostname zsfile]# awk '{print ARGC}' 1111 #awk 表示一个参数 1111表示一个参数
  30. 2
  31. 2
  32. 2
  33. [root@newhostname zsfile]# awk '{print ARGC}' 1111 123.txt #awk表示1个参数,1111表示一个参数,123.txt表示一个参数,所以输出结果为“3”
  34. 3
  35. 3
  36. 3
  37. 3
  38. [root@newhostname zsfile]# awk 'BEGIN {print ARGC}' /etc/fstab /etc/inittab
  39. 3

变量是可以在action内定义的,但是不利于写shell脚本,因为一般action都是有单引号引起来的,在shell内单引号是强引用,无法很好地使用shell变量(是shell变量非awk变量)

printf的用法(格式化字符串输出,比print更强大的输出方式,printf实际上也是一个linux命令):

printf的格式和特性:printf “FORMAT”, item1, item2, …

(1) 必须指定FORMAT
(2) 不会自动换行,需要显式给出换行控制符,
(3) FORMAT中需要分别为后面每个item指定格式符

printf的格式符:

%c: 显示字符的ASCII码
%d, %i: 显示十进制整数
%e, %E:显示科学计数法数值
%f:显示为浮点数
%g, %G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数
%%: 显示%自身

修饰符:

#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f
-: 左对齐(默认右对齐,对字符串你操作) %-15s
+:显示数值的正负符号 %+d

下面我们来用printf来举例:

printf字符串的格式化

  1. [root@joker-6-01 ~]# awk -F: '{printf "%s - ",$1}' /etc/passwd #printf 后面的%s代表的是$1,在这里$1不仅可以是列,还可以是变量、字符串
  2. root - bin - daemon - adm - lp - sync - shutdown - halt - mail - uucp - operator - games - gopher - ftp - nobody - dbus - usbmuxd - rpc - rtkit - avahi-autoipd - vcsa - abrt - rpcuser - nfsnobody - haldaemon - ntp - apache - saslauth - postfix - gdm - pulse - sshd - tcpdump - ee - rr - wang - wang1 - wang2 - wang3 - [root@joker-6-01 ~]#
  3. 由以上输出我们可以看出,printf是不会换行的,如果要换行 printf引号呢最后要添加
  4. [root@joker-6-01 ~]# awk -F: '{printf "%s - ",$1}' /etc/passwd | head -5 #添加 ,(因为条目太多,所以在这里我把条目限定在了5行,后面的示例也都这样操作)
  5. root -
  6. bin -
  7. daemon -
  8. adm -
  9. lp -
  10. 每一条记录执行完都会换行

printf的使用修饰符

  1. [root@joker-6-01 ~]# awk -F: '{printf "Username:%s,UID:%d ",$1,$3}' /etc/passwd | head -5
  2. Username:root,UID:0
  3. Username:bin,UID:1
  4. Username:daemon,UID:2
  5. Username:adm,UID:3
  6. Username:lp,UID:4
  7. 在这里我们使用字符串的格式化输出,但是输出结果并不直观,下面我们可以使用修饰符进行分割。
  8. [root@joker-6-01 ~]# awk -F: '{printf "Username:%-20sUID:%d ",$1,$3}' /etc/passwd | head -5 #%-20s :20表示最大长度,“-”表示左对齐
  9. Username:root UID:0
  10. Username:bin UID:1
  11. Username:daemon UID:2
  12. Username:adm UID:3
  13. Username:lp UID:4
  14. 输出的结果很明显
  15. [root@joker-6-01 ~]# awk -F: '{printf "Username:%20sUID:%d ",$1,$3}' /etc/passwd | head -5 #不加“-”的表示默认右对齐,在这里只是一个示例,没有任何意义
  16. Username: rootUID:0
  17. Username: binUID:1
  18. Username: daemonUID:2
  19. Username: admUID:3
  20. Username: lpUID:4
  21. 在这种环境下,使用右对齐显示不是我们要的,在这里我只是想标清楚,什么是左对齐,什么是右对齐
  22. 接下来我们示范一下浮点数的表示方法
  23. [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%f ",3.1234}'
  24. 3.123400
  25. [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%f ",3.1}'
  26. 3.100000
  27. 使用%f默认会甩出6位的小数位,那么我们使用修饰符来限定位数,关于BEGIN,在这里的意思是只执行一遍指令,并且不需要读取文件,BEGIN的真正含义是在读取文件之前执行的操作,我们在这里先不管,后面会讲解
  28. [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%8.3f ",3.1}' #8代表整数字符的宽度;.3代表小数的位数
  29. 3.100
  30. [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%08.3f ",3.1}' #08指如果整数位不足8位用0来代表空白
  31. 0003.100
  32. 浮点数的修饰一般我们做普通运维用不到,一般用的比较多的还是%s %d这两个

AWK的运算符:在action内执行

算术操作符:

x+y, x-y, x*y, x/y, x^y, x%y
-x: 转换为负数
+x: 转换为数值
字符串操作符:没有符号的操作符,字符串连接

赋值操作符:

=, +=, -=, *=, /=, %=, ^=
++, —

比较操作符:

==, !=, >, >=, <, <=
模式匹配符:
~:左边是否和右边匹配包含 !~:是否不匹配

逻辑操作符:

与&&,或||,非!

不多说了,直接举例:

  1. [root@joker-6-01 ~]# awk -F: '$0 ~ /root/{print $1}' /etc/passwd # “~” 匹配运算符
  2. root
  3. operator
  4. 大括号前面的这一部分,代表的就是最开始所说的“pattern”,这部分的的实际作用就是用来匹配指定记录。上面的含义就是 $0(整条记录)内是否有匹配root的记录,我们在这里使用的“root”是一个实际的字符串,在这里我们也可以使用正则表达式来匹配,我们使用/regex/的形式来表示匹配,我们来做个演示。
  5. [root@joker-6-01 ~]# cat /etc/passwd | tail -10 #现实passwd的后10行,我们将对这段字符进行操作
  6. gdm:x:42:42::/var/lib/gdm:/sbin/nologin
  7. pulse:x:497:496:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
  8. sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
  9. tcpdump:x:72:72::/:/sbin/nologin
  10. ee:x:500:500:dd,ff,aa,qwe:/home/ee:/bin/bash
  11. rr:x:501:502::/home/rr:/bin/bash
  12. wang:x:1010:1010::/app/wangs:/bin/bash
  13. wang1:x:1014:1011::/home/wang1:/bin/bash
  14. wang2:x:1012:1012::/home/wang2:/bin/bash
  15. wang3:x:1013:1013::/home/wang3:/bin/bash
  16. [root@joker-6-01 ~]#cat /etc/passwd | tail -10| awk '$0 ~ /^t.+n$/{print $0}'
  17. tcpdump:x:72:72::/:/sbin/nologin
  18. “/^t.+n$/” 代表的开头是“t”结尾为“n”的记录。
  19. 我们再来做一个不配“t”结尾为“n”的记录的示例:
  20. [root@joker-6-01 ~]# cat /etc/passwd | tail -10 | awk '$0 !~ /^t.+n$/{print $0}' # “!~” 表示不匹配,也就是说,不匹配的记录,awk认为是我们需要的数据
  21. gdm:x:42:42::/var/lib/gdm:/sbin/nologin
  22. pulse:x:497:496:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
  23. sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
  24. ee:x:500:500:dd,ff,aa,qwe:/home/ee:/bin/bash
  25. rr:x:501:502::/home/rr:/bin/bash
  26. wang:x:1010:1010::/app/wangs:/bin/bash
  27. wang1:x:1014:1011::/home/wang1:/bin/bash
  28. wang2:x:1012:1012::/home/wang2:/bin/bash
  29. wang3:x:1013:1013::/home/wang3:/bin/bash
  30. 我们再action内做算数运算
  31. [root@joker-6-01 ~]# awk 'BEGIN{print 2+2}'
  32. 4
  33. [root@joker-6-01 ~]# awk 'BEGIN{print 2*3}'
  34. 6
  35. [root@joker-6-01 ~]# awk 'BEGIN{print 2%3}'
  36. 2
  37. [root@joker-6-01 ~]# awk 'BEGIN{print 2**3}'
  38. 8
  39. 然后我这里有个坑:
  40. [root@joker-6-01 ~]# awk 'BEGIN{i=0;print ++i,i}' #限制性i+1 然后在输出i
  41. 1 1
  42. [root@joker-6-01 ~]# awk 'BEGIN{i=0;print i++,i}' #先输出 i 然后再执行 i+1,所以这两个结果不同
  43. 0 1
  44. [root@joker-6-01 zsfile]# awk -F: '$3 == 0' /etc/passwd #以:为分隔符,如果第三列为0,那么打印这一样,省略action则表示打印整条记录
  45. root:x:0:0:root:/root:/bin/bash
  46. 逻辑运算符的使用方法
  47. [root@joker-6-01 zsfile]# awk -F: '$3 >=0 && $3<=100{print $1}' /etc/passwd #uid大于等于0,小于等于100的记录,打印第一列
  48. root
  49. bin
  50. daemon
  51. adm
  52. lp
  53. sync
  54. shutdown
  55. halt
  56. mail
  57. uucp
  58. operator
  59. games
  60. gopher
  61. ftp
  62. nobody
  63. dbus
  64. rpc
  65. vcsa
  66. rpcuser
  67. haldaemon
  68. ntp
  69. apache
  70. postfix
  71. gdm
  72. sshd
  73. tcpdump
  74. [root@joker-6-01 zsfile]# awk -F: '!($3==0) && NR==3 {print $1}' /etc/passwd #这句表达的意思:取第三行,如果第三列不等于0,就打印该行,否则不操作。
  75. daemon

 

2、awk [options] ‘BEGIN{ action;… } pattern{ action;… } END{action;… }’ file …的详细使用方法

BEGIN/END模式
BEGIN{}: 仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次

示例:

  1. [root@joker-6-01 zsfile]# awk -F : 'BEGIN {printf "USER %-16sUSERID ",""}/^(t|p)/ {printf "%-20s %s ",$1,$3}END{printf "end%-18sfile ",""}' /etc/passwd
  2. 执行结果:
  3. USER USERID #BEGIN开始打印一行
  4. postfix 89
  5. pulse 497
  6. tcpdump 72
  7. end file #END执行完后打印
  8. if的示例:

三、awk的高阶用法

一般这种模式是用来处理一些判断或者循环事件的。

1、awk的判断语句(一般在action内使用)

awk控制语句——if-else

if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else{statement3}

awk的三元表达式,可用作变量赋值的判断

selector?if-true-expression:if-false-expression

  1. [root@joker-6-01 zsfile]# awk -F: '{if($3 >=100)print $1,$3}' /etc/passwd #判断如果第三列大于100(passwd中的uid值),打印这个记录的第一列和第三列
  2. usbmuxd 113
  3. rtkit 499
  4. avahi-autoipd 170
  5. abrt 173
  6. nfsnobody 65534
  7. saslauth 498
  8. pulse 497
  9. 我们定义两个变量,分别判断两个值的大小
  10. [root@joker-6-01 zsfile]# awk 'BEGIN{a=1;b=2;if(a>b){print "ok"}else if(a==b){print"a=b"}else {print "no"}}'
  11. no
  12. [root@joker-6-01 zsfile]# awk 'BEGIN{a=2;b=2;if(a>b){print "ok"}else if(a==b){print"a=b"}else {print "no"}}'
  13. a=b
  14. [root@joker-6-01 zsfile]# awk 'BEGIN{a=2;b=1;if(a>b){print "ok"}else if(a==b){print"a=b"}else {print "no"}}'
  15. ok
  16. 三元表达式的用法:
  17. [root@joker-6-01 zsfile]# awk 'BEGIN{a=1;b=2;a>b?a=3:b=3;print a,b}'
  18. 1 3

2、while循环

while(condition){statement;…}

do-while循环

do {statement;…}while(condition)
这种形式的循环表达的意思是,无论什么样的条件都会先执行一次循环,然后再判断while条件的真假。

  1. [root@joker-6-01 zsfile]# awk -v a=4 'BEGIN{while(a>0){ print a;a-=1 }}' #我没有想出一个应用场景啊,就用一个简单循环代替了。语法就是这么写
  2. 4
  3. 3
  4. 2
  5. 1
  6. d0-while用法
  7. [root@joker-6-01 zsfile]# awk 'BEGIN{total=0;i=0;do{total+=i;i++}while(i<=100);print total}' #计算前1-100的和
  8. 5050

3、for循环

for(expr1;expr2;expr3) {statement;…}
for(variable assignment;condition;iteration process){for-body}

  1. 两种语法:1、for i in array #这种方法,待会写了数组再谈
  2. 2for( i=x;i<=100;i++)
  3. [root@newhostname zsfile]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /boot/grub2/grub.cfg #遍历一个文件
  4. linux16 7
  5. /vmlinuz-3.10.0-693.el7.x86_64 30
  6. root=/dev/mapper/centos_joker--7--01-root 41
  7. ro 2
  8. rd.lvm.lv=centos_joker-7-01/root 32
  9. rd.lvm.lv=centos_joker-7-01/swap 32
  10. rhgb 4
  11. quiet 5
  12. linux16 7
  13. /vmlinuz-0-rescue-77b790ce63d24178bd4d95027a1bd2e9 50
  14. root=/dev/mapper/centos_joker--7--01-root 41
  15. ro 2
  16. rd.lvm.lv=centos_joker-7-01/root 32
  17. rd.lvm.lv=centos_joker-7-01/swap 32
  18. rhgb 4
  19. quiet 5

4、switch语句(相当于shell内的case语句)

switch(expression) {case VALUE1 or /REGEXP/:statement1; case VALUE2 or /REGEXP2/: statement2;…; default: statementn}

break [n]        跳出整个循环
continue [n]  跳过本次循环执行下次循环
next    提前结束对本行处理而直接进入下一行处理(awk自身循环)

  1. [root@newhostname zsfile]# awk -F: '{if($3==0) next; print $1,$3}' /etc/passwd | head -5 #打印非root用户
  2. bin 1
  3. daemon 2
  4. adm 3
  5. lp 4
  6. sync 5

这些控制语句是不是很眼熟,不论是什么语言都会有这些,只不过是表达形式的不同而已,原理都是一样的。

5、数组

awk的数组也分有序数组和关联数组两种
如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”

  1. awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}' #定义一个数组,并打印
  2. awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}' #便利一个数组的下标,注意,数组名不加[]表示数组下标的序列

6、awk的函数(常用的)

rand():返回0和1之间一个随机数,想用多少为的随机数只需init(rand()*num)即可,注意,如果要调用rand()函数,那么前面必须调用srand(),初始化一次随机值
length([s]):返回指定字符串的长度
sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s
gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2,…

  1. [root@newhostname zsfile]# awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }' #输出10个100以内的随机数
  2. 52
  3. 68
  4. 13
  5. 38
  6. 95
  7. 28
  8. 59
  9. 45
  10. 84
  11. 19
  12. [root@newhostname zsfile]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$1)' #查找替换全部的:为-
  13. 2008-08-08 08:08:08
  14. [root@newhostname zsfile]# echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)' #查找替换第一个:为-
  15. 2008-08:08 08:08:08
  16. [root@newhostname zsfile]# netstat -tan | awk '/^tcp>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}' #将第5列分割的字符串保存到数组ip中,并将有ip的下标变量付给count数组, 用for i in 遍历这个count并打印出ip
  17. 0.0.0.0 4
  18. 172.18.101.180 1

7、awk函数

格式:
function name ( parameter, parameter, … ) {
statements
return expression
}

和其他语言的格式基本相同,用法也差不多,这里不多说了。

8、awk中调用shell命令,可以使用system()函数

  1. [root@newhostname zsfile]# awk BEGIN'{system("hostname") }'
  2. newhostname

四、最后了,我们现在再说这种用法 :awk [options] -f ‘a program file’ file …

其实很简单就是讲awk的语句存到文件内,然后使用 awk -f来调用,就像shell调用shell脚本一样

  1. [root@newhostname zsfile]# cat test_awk.awk
  2. #! /usr/bin/awk
  3. {if($3>=1000)print $1,$3}
  4. [root@newhostname zsfile]# awk -f test_awk.awk /etc/passwd
  5. systemd-network:x:192:192:systemd Management:/:/sbin/nologin
  6. dbus:x:81:81:System bus:/:/sbin/nologin
  7. polkitd:x:999:997:User polkitd:/:/sbin/nologin
  8. colord:x:998:996:User colord:/var/lib/colord:/sbin/nologin
  9. libstoragemgmt:x:997:994:daemon for
  10. pulse:x:171:171:PulseAudio Daemon:/var/run/pulse:/sbin/nologin
  11. tss:x:59:59:Account by
  12. geoclue:x:994:989:User geoclue:/var/lib/geoclue:/sbin/nologin
  13. rpcuser:x:29:29:RPC User:/var/lib/nfs:/sbin/nologin
  14. nfsnobody:x:65534:65534:Anonymous User:/var/lib/nfs:/sbin/nologin
  15. sssd:x:993:988:User sssd:/:/sbin/nologin

输出一个文件内最大长度字段的长度,和这个字段的值

    1. [root@newhostname shell]# cat longest_field.sh
    2. #!/usr/bin/env awk -f
    3. #
    4. #********************************************************************
    5. #encoding -*-utf8-*-
    6. #Author: zhangshang
    7. #Date: 2018-01-04
    8. #URL: http://blog.vservices.top/myblog
    9. #QQ Numbers: 765030447
    10. #********************************************************************
    11. BEGIN {
    12. max=0
    13. }
    14. {
    15. split($0,field_record,FS);
    16. for(i in field_record)
    17. {if(length(field_record[i])>max){
    18. max=length(field_record[i]);max_field=field_record[i]}
    19. }
    20. }
    21. END{
    22. print max_field,max
    23. }
    24. #max=i;
    25. [root@newhostname shell]# cat ~/112233 #查看文本
    26. aaa:asdf:ddddddddd
    27. z:asdfasdfasd:asdfasdfasdfasdf:asdfz:ddd
    28. cccccccccccccccccc:eeeeeee:1111111:
    29. [root@newhostname shell]# awk -F: -f longest_field.sh ~/112233 #awk调用脚本
    30. cccccccccccccccccc 18

一、awk简介

awk是由3个人开发的:Aho, Weinberger, Kernighan;该功能主要是用来生成报告和格式化文本输出。它有多个版本:New awk(nawk),GNU awk( gawk)。我们通常在linux上使用的awk是基于GNU的awk。awk不只是一个命令,其真实,为一门语言,循环、数组、条件判断样样功能都有,功能非常强大,当然功能强大了,那么必定复杂。

二、基本用法:

awk [options] ‘program’ var=value file…
awk [options] ‘BEGIN{ action;… } pattern{ action;… } END{action;… }’ file …
awk [options] -f ‘a program file’ file …  (读取一个存有awk规则预存文件,再对指定文件进行处理)   这种用法,最后再说

options:

-F 指明输入时用到的字段分隔符(awk默认的分隔符就是空白字符)
-v var=value: 自定义变量   (awk的变量也分内置变量和自定义变量两种)

内置变量:

FS:输入字段分隔符,默认为空白字符
OFS:输出字段分隔符,默认为空白字符
RS:输入记录分隔符,指定输入时的换行符
ORS:输出记录分隔符,输出时用指定符号代替换行符
NF:字段数量
NR:记录号
FNR:各文件分别计数,记录号
FILENAME:当前文件名
ARGC:命令行参数的个数
ARGV:数组,保存的是命令行所给定的各参数

注意:虽然为内置变量,但是内置变量也可以用-v来声明初始值

1、awk [options] ‘program’ var=value file…用法的详细说明

program: pattern{action statements;..} #program由pattern和action两部分来组成

pattern和action:

• pattern部分决定动作语句何时触发及触发事件(也可以理解为匹配,用来过滤记录的)BEGIN,END
• action statements对数据进行处理,放在{}内指明print, printf

分割符、域和记录:

• awk执行时,由分隔符分隔的字段(域)标记$1,$2..$n称为域标识。$0为所有域,注意:和shell中变量$符含义不同
• 文件的每一行称为记录(一般的一行被称作一条记录)
• 省略action,则默认执行 print $0 的操作($0表示一整条记录,print表示打印输出的意思)

实例1,显示源输出的指定列:

  1. [root@newhostname /]# df | grep /dev/sd #先查看一下源标准输出
  2. /dev/sda1 1038336 162080 876256 16% /boot
  3. /dev/sdb3 3135488 135364 3000124 5% /mnt/xfs
  4. /dev/sdb2 3030800 9236 2847896 1% /mnt/ext4
  5. [root@newhostname /]# df | grep /sd | awk '{print $1"==="$5}'
  6. /dev/sda1===16%
  7. /dev/sdb3===5%
  8. /dev/sdb2===1%
  9. #$1为输出的第一列,$5为第5列,awk的默认字符是空表字符, 两列中间的等号为加入的字符串“===”

 实例2,使用awk的内置变量:

  1. [root@newhostname /]# awk -v FS=':' '{print $1,FS,$3}' /etc/passwd | head -5 #我们使用内置变量FS来作为分隔符
  2. root : 0
  3. bin : 1
  4. daemon : 2
  5. adm : 3
  6. lp : 4
  7. [root@newhostname /]# awk -F: '{print $1,FS,$3}' /etc/passwd | head -5 #我们使用-F option来指定分隔符
  8. root : 0
  9. bin : 1
  10. daemon : 2
  11. adm : 3
  12. lp : 4
  13. #由上面两个结果来看,其意义是一样的, 可以使用 -v 直接声明字段的分隔符,也可以用-F来指定。而在action内,变量是可以直接被调用的 ,注意,action内不要看走眼,如果是字符串的话,需要加“”“,直接输入的字符会当做变量来处理。

OFS变量的作用:

  1. [root@newhostname /]# awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd | head -5 #OFS输出字段分隔符,默认为空白,这里我们指定为“:”
  2. root:0:/bin/bash
  3. bin:1:/sbin/nologin
  4. daemon:2:/sbin/nologin
  5. adm:3:/sbin/nologin
  6. lp:4:/sbin/nologin
  7. [root@newhostname /]# awk -v FS=':' '{print $1,$3,$7}' /etc/passwd | head -5 #我们不指定OFS两段命令一对比,很明显,下面输出的使用的默认输出分隔符为空白。
  8. root 0 /bin/bash
  9. bin 1 /sbin/nologin
  10. daemon 2 /sbin/nologin
  11. adm 3 /sbin/nologin
  12. lp 4 /sbin/nologin

RS、ORS变量的应用:

  1. [root@newhostname zsfile]# cat 123.txt #文件的原输出
  2. dddd:112233:1000:1000 /home/bash:/bin/bash
  3. [root@newhostname zsfile]# awk -v RS=':' '{print }' ./123.txt #定义RS变更记录分隔符(默认的分隔符是换行符)
  4. dddd
  5. 112233
  6. 1000
  7. 1000 /home/bash
  8. /bin/bash
  9. [root@newhostname zsfile]# awk -v RS=':' -v ORS='|-|' '{print }' ./123.txt #我们定义ORS来改变输出的分隔符
  10. dddd|-|112233|-|1000|-|1000 /home/bash|-|/bin/bash
  11. |-|[root@newhostname zsfile]#

RS的意义是改变处理文本之前的记录分隔符,当处理完记录之后,输出记录分隔符(ORS)如果未定义,则还是现实原来默认的记录分隔符去显示,即默认的换行符。

实例3,NF字段数量,NR行号变量,FNR分文件行号变量,FILENAME当前的文件名,ARGC命令行参数的个数

  1. [root@newhostname zsfile]# vim 1111
  2. [root@newhostname zsfile]# cat 1111
  3. aa bb cc dd ee
  4. 11 22 33 44 55
  5. 33 22 11 ss 44
  6. [root@newhostname zsfile]# awk '{print NR,NF}' 1111 #NR表示第几行,NF为列的总数
  7. 1 5
  8. 2 5
  9. 3 5
  10. [root@newhostname zsfile]# awk '{print NR,$NF}' 1111 #$NF表示最后一列
  11. 1 ee
  12. 2 55
  13. 3 44
  14. [root@newhostname zsfile]# awk '{print NR,$NF}' 1111 123.txt #如果使用awk同时对多个文件进行处理,那么使用NR,最后的出列结果会合并成1个,而不会按文件分开,如果要按文件分开,要是用FNR
  15. 1 ee
  16. 2 55
  17. 3 44
  18. 4 /home/bash:/bin/bash
  19. [root@newhostname zsfile]# awk '{print FNR,$NF}' 1111 123.txt #使用FNR按文件分开
  20. 1 ee
  21. 2 55
  22. 3 44
  23. 1 /home/bash:/bin/bash
  24. [root@newhostname zsfile]# awk '{print FILENAME,FNR,$NF}' 1111 123.txt #FILENAME 在输出列输出文件的名字
  25. 1111 1 ee
  26. 1111 2 55
  27. 1111 3 44
  28. 123.txt 1 /home/bash:/bin/bash
  29. [root@newhostname zsfile]# awk '{print ARGC}' 1111 #awk 表示一个参数 1111表示一个参数
  30. 2
  31. 2
  32. 2
  33. [root@newhostname zsfile]# awk '{print ARGC}' 1111 123.txt #awk表示1个参数,1111表示一个参数,123.txt表示一个参数,所以输出结果为“3”
  34. 3
  35. 3
  36. 3
  37. 3
  38. [root@newhostname zsfile]# awk 'BEGIN {print ARGC}' /etc/fstab /etc/inittab
  39. 3

变量是可以在action内定义的,但是不利于写shell脚本,因为一般action都是有单引号引起来的,在shell内单引号是强引用,无法很好地使用shell变量(是shell变量非awk变量)

printf的用法(格式化字符串输出,比print更强大的输出方式,printf实际上也是一个linux命令):

printf的格式和特性:printf “FORMAT”, item1, item2, …

(1) 必须指定FORMAT
(2) 不会自动换行,需要显式给出换行控制符,
(3) FORMAT中需要分别为后面每个item指定格式符

printf的格式符:

%c: 显示字符的ASCII码
%d, %i: 显示十进制整数
%e, %E:显示科学计数法数值
%f:显示为浮点数
%g, %G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数
%%: 显示%自身

修饰符:

#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f
-: 左对齐(默认右对齐,对字符串你操作) %-15s
+:显示数值的正负符号 %+d

下面我们来用printf来举例:

printf字符串的格式化

  1. [root@joker-6-01 ~]# awk -F: '{printf "%s - ",$1}' /etc/passwd #printf 后面的%s代表的是$1,在这里$1不仅可以是列,还可以是变量、字符串
  2. root - bin - daemon - adm - lp - sync - shutdown - halt - mail - uucp - operator - games - gopher - ftp - nobody - dbus - usbmuxd - rpc - rtkit - avahi-autoipd - vcsa - abrt - rpcuser - nfsnobody - haldaemon - ntp - apache - saslauth - postfix - gdm - pulse - sshd - tcpdump - ee - rr - wang - wang1 - wang2 - wang3 - [root@joker-6-01 ~]#
  3. 由以上输出我们可以看出,printf是不会换行的,如果要换行 printf引号呢最后要添加
  4. [root@joker-6-01 ~]# awk -F: '{printf "%s - ",$1}' /etc/passwd | head -5 #添加 ,(因为条目太多,所以在这里我把条目限定在了5行,后面的示例也都这样操作)
  5. root -
  6. bin -
  7. daemon -
  8. adm -
  9. lp -
  10. 每一条记录执行完都会换行

printf的使用修饰符

  1. [root@joker-6-01 ~]# awk -F: '{printf "Username:%s,UID:%d ",$1,$3}' /etc/passwd | head -5
  2. Username:root,UID:0
  3. Username:bin,UID:1
  4. Username:daemon,UID:2
  5. Username:adm,UID:3
  6. Username:lp,UID:4
  7. 在这里我们使用字符串的格式化输出,但是输出结果并不直观,下面我们可以使用修饰符进行分割。
  8. [root@joker-6-01 ~]# awk -F: '{printf "Username:%-20sUID:%d ",$1,$3}' /etc/passwd | head -5 #%-20s :20表示最大长度,“-”表示左对齐
  9. Username:root UID:0
  10. Username:bin UID:1
  11. Username:daemon UID:2
  12. Username:adm UID:3
  13. Username:lp UID:4
  14. 输出的结果很明显
  15. [root@joker-6-01 ~]# awk -F: '{printf "Username:%20sUID:%d ",$1,$3}' /etc/passwd | head -5 #不加“-”的表示默认右对齐,在这里只是一个示例,没有任何意义
  16. Username: rootUID:0
  17. Username: binUID:1
  18. Username: daemonUID:2
  19. Username: admUID:3
  20. Username: lpUID:4
  21. 在这种环境下,使用右对齐显示不是我们要的,在这里我只是想标清楚,什么是左对齐,什么是右对齐
  22. 接下来我们示范一下浮点数的表示方法
  23. [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%f ",3.1234}'
  24. 3.123400
  25. [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%f ",3.1}'
  26. 3.100000
  27. 使用%f默认会甩出6位的小数位,那么我们使用修饰符来限定位数,关于BEGIN,在这里的意思是只执行一遍指令,并且不需要读取文件,BEGIN的真正含义是在读取文件之前执行的操作,我们在这里先不管,后面会讲解
  28. [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%8.3f ",3.1}' #8代表整数字符的宽度;.3代表小数的位数
  29. 3.100
  30. [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%08.3f ",3.1}' #08指如果整数位不足8位用0来代表空白
  31. 0003.100
  32. 浮点数的修饰一般我们做普通运维用不到,一般用的比较多的还是%s %d这两个

AWK的运算符:在action内执行

算术操作符:

x+y, x-y, x*y, x/y, x^y, x%y
-x: 转换为负数
+x: 转换为数值
字符串操作符:没有符号的操作符,字符串连接

赋值操作符:

=, +=, -=, *=, /=, %=, ^=
++, —

比较操作符:

==, !=, >, >=, <, <=
模式匹配符:
~:左边是否和右边匹配包含 !~:是否不匹配

逻辑操作符:

与&&,或||,非!

不多说了,直接举例:

  1. [root@joker-6-01 ~]# awk -F: '$0 ~ /root/{print $1}' /etc/passwd # “~” 匹配运算符
  2. root
  3. operator
  4. 大括号前面的这一部分,代表的就是最开始所说的“pattern”,这部分的的实际作用就是用来匹配指定记录。上面的含义就是 $0(整条记录)内是否有匹配root的记录,我们在这里使用的“root”是一个实际的字符串,在这里我们也可以使用正则表达式来匹配,我们使用/regex/的形式来表示匹配,我们来做个演示。
  5. [root@joker-6-01 ~]# cat /etc/passwd | tail -10 #现实passwd的后10行,我们将对这段字符进行操作
  6. gdm:x:42:42::/var/lib/gdm:/sbin/nologin
  7. pulse:x:497:496:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
  8. sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
  9. tcpdump:x:72:72::/:/sbin/nologin
  10. ee:x:500:500:dd,ff,aa,qwe:/home/ee:/bin/bash
  11. rr:x:501:502::/home/rr:/bin/bash
  12. wang:x:1010:1010::/app/wangs:/bin/bash
  13. wang1:x:1014:1011::/home/wang1:/bin/bash
  14. wang2:x:1012:1012::/home/wang2:/bin/bash
  15. wang3:x:1013:1013::/home/wang3:/bin/bash
  16. [root@joker-6-01 ~]#cat /etc/passwd | tail -10| awk '$0 ~ /^t.+n$/{print $0}'
  17. tcpdump:x:72:72::/:/sbin/nologin
  18. “/^t.+n$/” 代表的开头是“t”结尾为“n”的记录。
  19. 我们再来做一个不配“t”结尾为“n”的记录的示例:
  20. [root@joker-6-01 ~]# cat /etc/passwd | tail -10 | awk '$0 !~ /^t.+n$/{print $0}' # “!~” 表示不匹配,也就是说,不匹配的记录,awk认为是我们需要的数据
  21. gdm:x:42:42::/var/lib/gdm:/sbin/nologin
  22. pulse:x:497:496:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
  23. sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
  24. ee:x:500:500:dd,ff,aa,qwe:/home/ee:/bin/bash
  25. rr:x:501:502::/home/rr:/bin/bash
  26. wang:x:1010:1010::/app/wangs:/bin/bash
  27. wang1:x:1014:1011::/home/wang1:/bin/bash
  28. wang2:x:1012:1012::/home/wang2:/bin/bash
  29. wang3:x:1013:1013::/home/wang3:/bin/bash
  30. 我们再action内做算数运算
  31. [root@joker-6-01 ~]# awk 'BEGIN{print 2+2}'
  32. 4
  33. [root@joker-6-01 ~]# awk 'BEGIN{print 2*3}'
  34. 6
  35. [root@joker-6-01 ~]# awk 'BEGIN{print 2%3}'
  36. 2
  37. [root@joker-6-01 ~]# awk 'BEGIN{print 2**3}'
  38. 8
  39. 然后我这里有个坑:
  40. [root@joker-6-01 ~]# awk 'BEGIN{i=0;print ++i,i}' #限制性i+1 然后在输出i
  41. 1 1
  42. [root@joker-6-01 ~]# awk 'BEGIN{i=0;print i++,i}' #先输出 i 然后再执行 i+1,所以这两个结果不同
  43. 0 1
  44. [root@joker-6-01 zsfile]# awk -F: '$3 == 0' /etc/passwd #以:为分隔符,如果第三列为0,那么打印这一样,省略action则表示打印整条记录
  45. root:x:0:0:root:/root:/bin/bash
  46. 逻辑运算符的使用方法
  47. [root@joker-6-01 zsfile]# awk -F: '$3 >=0 && $3<=100{print $1}' /etc/passwd #uid大于等于0,小于等于100的记录,打印第一列
  48. root
  49. bin
  50. daemon
  51. adm
  52. lp
  53. sync
  54. shutdown
  55. halt
  56. mail
  57. uucp
  58. operator
  59. games
  60. gopher
  61. ftp
  62. nobody
  63. dbus
  64. rpc
  65. vcsa
  66. rpcuser
  67. haldaemon
  68. ntp
  69. apache
  70. postfix
  71. gdm
  72. sshd
  73. tcpdump
  74. [root@joker-6-01 zsfile]# awk -F: '!($3==0) && NR==3 {print $1}' /etc/passwd #这句表达的意思:取第三行,如果第三列不等于0,就打印该行,否则不操作。
  75. daemon

 

2、awk [options] ‘BEGIN{ action;… } pattern{ action;… } END{action;… }’ file …的详细使用方法

BEGIN/END模式
BEGIN{}: 仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次

示例:

  1. [root@joker-6-01 zsfile]# awk -F : 'BEGIN {printf "USER %-16sUSERID ",""}/^(t|p)/ {printf "%-20s %s ",$1,$3}END{printf "end%-18sfile ",""}' /etc/passwd
  2. 执行结果:
  3. USER USERID #BEGIN开始打印一行
  4. postfix 89
  5. pulse 497
  6. tcpdump 72
  7. end file #END执行完后打印
  8. if的示例:

三、awk的高阶用法

一般这种模式是用来处理一些判断或者循环事件的。

1、awk的判断语句(一般在action内使用)

awk控制语句——if-else

if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else{statement3}

awk的三元表达式,可用作变量赋值的判断

selector?if-true-expression:if-false-expression

  1. [root@joker-6-01 zsfile]# awk -F: '{if($3 >=100)print $1,$3}' /etc/passwd #判断如果第三列大于100(passwd中的uid值),打印这个记录的第一列和第三列
  2. usbmuxd 113
  3. rtkit 499
  4. avahi-autoipd 170
  5. abrt 173
  6. nfsnobody 65534
  7. saslauth 498
  8. pulse 497
  9. 我们定义两个变量,分别判断两个值的大小
  10. [root@joker-6-01 zsfile]# awk 'BEGIN{a=1;b=2;if(a>b){print "ok"}else if(a==b){print"a=b"}else {print "no"}}'
  11. no
  12. [root@joker-6-01 zsfile]# awk 'BEGIN{a=2;b=2;if(a>b){print "ok"}else if(a==b){print"a=b"}else {print "no"}}'
  13. a=b
  14. [root@joker-6-01 zsfile]# awk 'BEGIN{a=2;b=1;if(a>b){print "ok"}else if(a==b){print"a=b"}else {print "no"}}'
  15. ok
  16. 三元表达式的用法:
  17. [root@joker-6-01 zsfile]# awk 'BEGIN{a=1;b=2;a>b?a=3:b=3;print a,b}'
  18. 1 3

2、while循环

while(condition){statement;…}

do-while循环

do {statement;…}while(condition)
这种形式的循环表达的意思是,无论什么样的条件都会先执行一次循环,然后再判断while条件的真假。

  1. [root@joker-6-01 zsfile]# awk -v a=4 'BEGIN{while(a>0){ print a;a-=1 }}' #我没有想出一个应用场景啊,就用一个简单循环代替了。语法就是这么写
  2. 4
  3. 3
  4. 2
  5. 1
  6. d0-while用法
  7. [root@joker-6-01 zsfile]# awk 'BEGIN{total=0;i=0;do{total+=i;i++}while(i<=100);print total}' #计算前1-100的和
  8. 5050

3、for循环

for(expr1;expr2;expr3) {statement;…}
for(variable assignment;condition;iteration process){for-body}

  1. 两种语法:1、for i in array #这种方法,待会写了数组再谈
  2. 2for( i=x;i<=100;i++)
  3. [root@newhostname zsfile]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /boot/grub2/grub.cfg #遍历一个文件
  4. linux16 7
  5. /vmlinuz-3.10.0-693.el7.x86_64 30
  6. root=/dev/mapper/centos_joker--7--01-root 41
  7. ro 2
  8. rd.lvm.lv=centos_joker-7-01/root 32
  9. rd.lvm.lv=centos_joker-7-01/swap 32
  10. rhgb 4
  11. quiet 5
  12. linux16 7
  13. /vmlinuz-0-rescue-77b790ce63d24178bd4d95027a1bd2e9 50
  14. root=/dev/mapper/centos_joker--7--01-root 41
  15. ro 2
  16. rd.lvm.lv=centos_joker-7-01/root 32
  17. rd.lvm.lv=centos_joker-7-01/swap 32
  18. rhgb 4
  19. quiet 5

4、switch语句(相当于shell内的case语句)

switch(expression) {case VALUE1 or /REGEXP/:statement1; case VALUE2 or /REGEXP2/: statement2;…; default: statementn}

break [n]        跳出整个循环
continue [n]  跳过本次循环执行下次循环
next    提前结束对本行处理而直接进入下一行处理(awk自身循环)

  1. [root@newhostname zsfile]# awk -F: '{if($3==0) next; print $1,$3}' /etc/passwd | head -5 #打印非root用户
  2. bin 1
  3. daemon 2
  4. adm 3
  5. lp 4
  6. sync 5

这些控制语句是不是很眼熟,不论是什么语言都会有这些,只不过是表达形式的不同而已,原理都是一样的。

5、数组

awk的数组也分有序数组和关联数组两种
如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”

  1. awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}' #定义一个数组,并打印
  2. awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}' #便利一个数组的下标,注意,数组名不加[]表示数组下标的序列

6、awk的函数(常用的)

rand():返回0和1之间一个随机数,想用多少为的随机数只需init(rand()*num)即可,注意,如果要调用rand()函数,那么前面必须调用srand(),初始化一次随机值
length([s]):返回指定字符串的长度
sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s
gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2,…

  1. [root@newhostname zsfile]# awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }' #输出10个100以内的随机数
  2. 52
  3. 68
  4. 13
  5. 38
  6. 95
  7. 28
  8. 59
  9. 45
  10. 84
  11. 19
  12. [root@newhostname zsfile]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$1)' #查找替换全部的:为-
  13. 2008-08-08 08:08:08
  14. [root@newhostname zsfile]# echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)' #查找替换第一个:为-
  15. 2008-08:08 08:08:08
  16. [root@newhostname zsfile]# netstat -tan | awk '/^tcp>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}' #将第5列分割的字符串保存到数组ip中,并将有ip的下标变量付给count数组, 用for i in 遍历这个count并打印出ip
  17. 0.0.0.0 4
  18. 172.18.101.180 1

7、awk函数

格式:
function name ( parameter, parameter, … ) {
statements
return expression
}

和其他语言的格式基本相同,用法也差不多,这里不多说了。

8、awk中调用shell命令,可以使用system()函数

  1. [root@newhostname zsfile]# awk BEGIN'{system("hostname") }'
  2. newhostname

四、最后了,我们现在再说这种用法 :awk [options] -f ‘a program file’ file …

其实很简单就是讲awk的语句存到文件内,然后使用 awk -f来调用,就像shell调用shell脚本一样

  1. [root@newhostname zsfile]# cat test_awk.awk
  2. #! /usr/bin/awk
  3. {if($3>=1000)print $1,$3}
  4. [root@newhostname zsfile]# awk -f test_awk.awk /etc/passwd
  5. systemd-network:x:192:192:systemd Management:/:/sbin/nologin
  6. dbus:x:81:81:System bus:/:/sbin/nologin
  7. polkitd:x:999:997:User polkitd:/:/sbin/nologin
  8. colord:x:998:996:User colord:/var/lib/colord:/sbin/nologin
  9. libstoragemgmt:x:997:994:daemon for
  10. pulse:x:171:171:PulseAudio Daemon:/var/run/pulse:/sbin/nologin
  11. tss:x:59:59:Account by
  12. geoclue:x:994:989:User geoclue:/var/lib/geoclue:/sbin/nologin
  13. rpcuser:x:29:29:RPC User:/var/lib/nfs:/sbin/nologin
  14. nfsnobody:x:65534:65534:Anonymous User:/var/lib/nfs:/sbin/nologin
  15. sssd:x:993:988:User sssd:/:/sbin/nologin

输出一个文件内最大长度字段的长度,和这个字段的值

  1. [root@newhostname shell]# cat longest_field.sh
  2. #!/usr/bin/env awk -f
  3. #
  4. #********************************************************************
  5. #encoding -*-utf8-*-
  6. #Author: zhangshang
  7. #Date: 2018-01-04
  8. #URL: http://blog.vservices.top/myblog
  9. #QQ Numbers: 765030447
  10. #********************************************************************
  11. BEGIN {
  12. max=0
  13. }
  14. {
  15. split($0,field_record,FS);
  16. for(i in field_record)
  17. {if(length(field_record[i])>max){
  18. max=length(field_record[i]);max_field=field_record[i]}
  19. }
  20. }
  21. END{
  22. print max_field,max
  23. }
  24. #max=i;
  25. [root@newhostname shell]# cat ~/112233 #查看文本
  26. aaa:asdf:ddddddddd
  27. z:asdfasdfasd:asdfasdfasdfasdf:asdfz:ddd
  28. cccccccccccccccccc:eeeeeee:1111111:
  29. [root@newhostname shell]# awk -F: -f longest_field.sh ~/112233 #awk调用脚本
  30. cccccccccccccccccc 18
原文地址:https://www.cnblogs.com/momenglin/p/8483113.html