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,显示源输出的指定列:
- [root@newhostname /]# df | grep /dev/sd #先查看一下源标准输出
- /dev/sda1 1038336 162080 876256 16% /boot
- /dev/sdb3 3135488 135364 3000124 5% /mnt/xfs
- /dev/sdb2 3030800 9236 2847896 1% /mnt/ext4
- [root@newhostname /]# df | grep /sd | awk '{print $1"==="$5}'
- /dev/sda1===16%
- /dev/sdb3===5%
- /dev/sdb2===1%
- #$1为输出的第一列,$5为第5列,awk的默认字符是空表字符, 两列中间的等号为加入的字符串“===”
实例2,使用awk的内置变量:
- [root@newhostname /]# awk -v FS=':' '{print $1,FS,$3}' /etc/passwd | head -5 #我们使用内置变量FS来作为分隔符
- root : 0
- bin : 1
- daemon : 2
- adm : 3
- lp : 4
- [root@newhostname /]# awk -F: '{print $1,FS,$3}' /etc/passwd | head -5 #我们使用-F option来指定分隔符
- root : 0
- bin : 1
- daemon : 2
- adm : 3
- lp : 4
- #由上面两个结果来看,其意义是一样的, 可以使用 -v 直接声明字段的分隔符,也可以用-F来指定。而在action内,变量是可以直接被调用的 ,注意,action内不要看走眼,如果是字符串的话,需要加“”“,直接输入的字符会当做变量来处理。
OFS变量的作用:
- [root@newhostname /]# awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd | head -5 #OFS输出字段分隔符,默认为空白,这里我们指定为“:”
- root:0:/bin/bash
- bin:1:/sbin/nologin
- daemon:2:/sbin/nologin
- adm:3:/sbin/nologin
- lp:4:/sbin/nologin
- [root@newhostname /]# awk -v FS=':' '{print $1,$3,$7}' /etc/passwd | head -5 #我们不指定OFS两段命令一对比,很明显,下面输出的使用的默认输出分隔符为空白。
- root 0 /bin/bash
- bin 1 /sbin/nologin
- daemon 2 /sbin/nologin
- adm 3 /sbin/nologin
- lp 4 /sbin/nologin
RS、ORS变量的应用:
- [root@newhostname zsfile]# cat 123.txt #文件的原输出
- dddd:112233:1000:1000 /home/bash:/bin/bash
- [root@newhostname zsfile]# awk -v RS=':' '{print }' ./123.txt #定义RS变更记录分隔符(默认的分隔符是换行符)
- dddd
- 112233
- 1000
- 1000 /home/bash
- /bin/bash
- [root@newhostname zsfile]# awk -v RS=':' -v ORS='|-|' '{print }' ./123.txt #我们定义ORS来改变输出的分隔符
- dddd|-|112233|-|1000|-|1000 /home/bash|-|/bin/bash
- |-|[root@newhostname zsfile]#
RS的意义是改变处理文本之前的记录分隔符,当处理完记录之后,输出记录分隔符(ORS)如果未定义,则还是现实原来默认的记录分隔符去显示,即默认的换行符。
实例3,NF字段数量,NR行号变量,FNR分文件行号变量,FILENAME当前的文件名,ARGC命令行参数的个数
- [root@newhostname zsfile]# vim 1111
- [root@newhostname zsfile]# cat 1111
- aa bb cc dd ee
- 11 22 33 44 55
- 33 22 11 ss 44
- [root@newhostname zsfile]# awk '{print NR,NF}' 1111 #NR表示第几行,NF为列的总数
- 1 5
- 2 5
- 3 5
- [root@newhostname zsfile]# awk '{print NR,$NF}' 1111 #$NF表示最后一列
- 1 ee
- 2 55
- 3 44
- [root@newhostname zsfile]# awk '{print NR,$NF}' 1111 123.txt #如果使用awk同时对多个文件进行处理,那么使用NR,最后的出列结果会合并成1个,而不会按文件分开,如果要按文件分开,要是用FNR
- 1 ee
- 2 55
- 3 44
- 4 /home/bash:/bin/bash
- [root@newhostname zsfile]# awk '{print FNR,$NF}' 1111 123.txt #使用FNR按文件分开
- 1 ee
- 2 55
- 3 44
- 1 /home/bash:/bin/bash
- [root@newhostname zsfile]# awk '{print FILENAME,FNR,$NF}' 1111 123.txt #FILENAME 在输出列输出文件的名字
- 1111 1 ee
- 1111 2 55
- 1111 3 44
- 123.txt 1 /home/bash:/bin/bash
- [root@newhostname zsfile]# awk '{print ARGC}' 1111 #awk 表示一个参数 1111表示一个参数
- 2
- 2
- 2
- [root@newhostname zsfile]# awk '{print ARGC}' 1111 123.txt #awk表示1个参数,1111表示一个参数,123.txt表示一个参数,所以输出结果为“3”
- 3
- 3
- 3
- 3
- [root@newhostname zsfile]# awk 'BEGIN {print ARGC}' /etc/fstab /etc/inittab
- 3
变量是可以在action内定义的,但是不利于写shell脚本,因为一般action都是有单引号引起来的,在shell内单引号是强引用,无法很好地使用shell变量(是shell变量非awk变量)
printf的用法(格式化字符串输出,比print更强大的输出方式,printf实际上也是一个linux命令):
printf的格式和特性:printf “FORMAT”, item1, item2, …
(1) 必须指定FORMAT
(2) 不会自动换行,需要显式给出换行控制符,\n
(3) FORMAT中需要分别为后面每个item指定格式符
printf的格式符:
%c: 显示字符的ASCII码
%d, %i: 显示十进制整数
%e, %E:显示科学计数法数值
%f:显示为浮点数
%g, %G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数
%%: 显示%自身
修饰符:
#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f
-: 左对齐(默认右对齐,对字符串你操作) %-15s
+:显示数值的正负符号 %+d
下面我们来用printf来举例:
printf字符串的格式化
- [root@joker-6-01 ~]# awk -F: '{printf "%s - ",$1}' /etc/passwd #printf 后面的%s代表的是$1,在这里$1不仅可以是列,还可以是变量、字符串
- 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 ~]#
- 由以上输出我们可以看出,printf是不会换行的,如果要换行 printf引号呢最后要添加\n
- [root@joker-6-01 ~]# awk -F: '{printf "%s - \n",$1}' /etc/passwd | head -5 #添加\n,(因为条目太多,所以在这里我把条目限定在了5行,后面的示例也都这样操作)
- root -
- bin -
- daemon -
- adm -
- lp -
- 每一条记录执行完都会换行
printf的使用修饰符
- [root@joker-6-01 ~]# awk -F: '{printf "Username:%s,UID:%d\n",$1,$3}' /etc/passwd | head -5
- Username:root,UID:0
- Username:bin,UID:1
- Username:daemon,UID:2
- Username:adm,UID:3
- Username:lp,UID:4
- 在这里我们使用字符串的格式化输出,但是输出结果并不直观,下面我们可以使用修饰符进行分割。
- [root@joker-6-01 ~]# awk -F: '{printf "Username:%-20sUID:%d\n",$1,$3}' /etc/passwd | head -5 #%-20s :20表示最大长度,“-”表示左对齐
- Username:root UID:0
- Username:bin UID:1
- Username:daemon UID:2
- Username:adm UID:3
- Username:lp UID:4
- 输出的结果很明显
- [root@joker-6-01 ~]# awk -F: '{printf "Username:%20sUID:%d\n",$1,$3}' /etc/passwd | head -5 #不加“-”的表示默认右对齐,在这里只是一个示例,没有任何意义
- Username: rootUID:0
- Username: binUID:1
- Username: daemonUID:2
- Username: admUID:3
- Username: lpUID:4
- 在这种环境下,使用右对齐显示不是我们要的,在这里我只是想标清楚,什么是左对齐,什么是右对齐
- 接下来我们示范一下浮点数的表示方法
- [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%f\n",3.1234}'
- 3.123400
- [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%f\n",3.1}'
- 3.100000
- 使用%f默认会甩出6位的小数位,那么我们使用修饰符来限定位数,关于BEGIN,在这里的意思是只执行一遍指令,并且不需要读取文件,BEGIN的真正含义是在读取文件之前执行的操作,我们在这里先不管,后面会讲解
- [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%8.3f\n",3.1}' #8代表整数字符的宽度;.3代表小数的位数
- 3.100
- [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%08.3f\n",3.1}' #08指如果整数位不足8位用0来代表空白
- 0003.100
- 浮点数的修饰一般我们做普通运维用不到,一般用的比较多的还是%s %d这两个
AWK的运算符:在action内执行
算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x: 转换为负数
+x: 转换为数值
字符串操作符:没有符号的操作符,字符串连接
赋值操作符:
=, +=, -=, *=, /=, %=, ^=
++, —
比较操作符:
==, !=, >, >=, <, <=
模式匹配符:
~:左边是否和右边匹配包含 !~:是否不匹配
逻辑操作符:
与&&,或||,非!
不多说了,直接举例:
- [root@joker-6-01 ~]# awk -F: '$0 ~ /root/{print $1}' /etc/passwd # “~” 匹配运算符
- root
- operator
- 大括号前面的这一部分,代表的就是最开始所说的“pattern”,这部分的的实际作用就是用来匹配指定记录。上面的含义就是 $0(整条记录)内是否有匹配root的记录,我们在这里使用的“root”是一个实际的字符串,在这里我们也可以使用正则表达式来匹配,我们使用/regex/的形式来表示匹配,我们来做个演示。
- [root@joker-6-01 ~]# cat /etc/passwd | tail -10 #现实passwd的后10行,我们将对这段字符进行操作
- gdm:x:42:42::/var/lib/gdm:/sbin/nologin
- pulse:x:497:496:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
- sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
- tcpdump:x:72:72::/:/sbin/nologin
- ee:x:500:500:dd,ff,aa,qwe:/home/ee:/bin/bash
- rr:x:501:502::/home/rr:/bin/bash
- wang:x:1010:1010::/app/wangs:/bin/bash
- wang1:x:1014:1011::/home/wang1:/bin/bash
- wang2:x:1012:1012::/home/wang2:/bin/bash
- wang3:x:1013:1013::/home/wang3:/bin/bash
- [root@joker-6-01 ~]#cat /etc/passwd | tail -10| awk '$0 ~ /^t.+n$/{print $0}'
- tcpdump:x:72:72::/:/sbin/nologin
- “/^t.+n$/” 代表的开头是“t”结尾为“n”的记录。
- 我们再来做一个不配“t”结尾为“n”的记录的示例:
- [root@joker-6-01 ~]# cat /etc/passwd | tail -10 | awk '$0 !~ /^t.+n$/{print $0}' # “!~” 表示不匹配,也就是说,不匹配的记录,awk认为是我们需要的数据
- gdm:x:42:42::/var/lib/gdm:/sbin/nologin
- pulse:x:497:496:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
- sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
- ee:x:500:500:dd,ff,aa,qwe:/home/ee:/bin/bash
- rr:x:501:502::/home/rr:/bin/bash
- wang:x:1010:1010::/app/wangs:/bin/bash
- wang1:x:1014:1011::/home/wang1:/bin/bash
- wang2:x:1012:1012::/home/wang2:/bin/bash
- wang3:x:1013:1013::/home/wang3:/bin/bash
- 我们再action内做算数运算
- [root@joker-6-01 ~]# awk 'BEGIN{print 2+2}'
- 4
- [root@joker-6-01 ~]# awk 'BEGIN{print 2*3}'
- 6
- [root@joker-6-01 ~]# awk 'BEGIN{print 2%3}'
- 2
- [root@joker-6-01 ~]# awk 'BEGIN{print 2**3}'
- 8
- 然后我这里有个坑:
- [root@joker-6-01 ~]# awk 'BEGIN{i=0;print ++i,i}' #限制性i+1 然后在输出i
- 1 1
- [root@joker-6-01 ~]# awk 'BEGIN{i=0;print i++,i}' #先输出 i 然后再执行 i+1,所以这两个结果不同
- 0 1
- [root@joker-6-01 zsfile]# awk -F: '$3 == 0' /etc/passwd #以:为分隔符,如果第三列为0,那么打印这一样,省略action则表示打印整条记录
- root:x:0:0:root:/root:/bin/bash
- 逻辑运算符的使用方法
- [root@joker-6-01 zsfile]# awk -F: '$3 >=0 && $3<=100{print $1}' /etc/passwd #uid大于等于0,小于等于100的记录,打印第一列
- root
- bin
- daemon
- adm
- lp
- sync
- shutdown
- halt
- uucp
- operator
- games
- gopher
- ftp
- nobody
- dbus
- rpc
- vcsa
- rpcuser
- haldaemon
- ntp
- apache
- postfix
- gdm
- sshd
- tcpdump
- [root@joker-6-01 zsfile]# awk -F: '!($3==0) && NR==3 {print $1}' /etc/passwd #这句表达的意思:取第三行,如果第三列不等于0,就打印该行,否则不操作。
- daemon
2、awk [options] ‘BEGIN{ action;… } pattern{ action;… } END{action;… }’ file …的详细使用方法
BEGIN/END模式
BEGIN{}: 仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
示例:
- [root@joker-6-01 zsfile]# awk -F : 'BEGIN {printf "USER %-16sUSERID\n",""}/^(t|p)/ {printf "%-20s %s\n",$1,$3}END{printf "end%-18sfile\n",""}' /etc/passwd
- 执行结果:
- USER USERID #BEGIN开始打印一行
- postfix 89
- pulse 497
- tcpdump 72
- end file #END执行完后打印
- 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
- [root@joker-6-01 zsfile]# awk -F: '{if($3 >=100)print $1,$3}' /etc/passwd #判断如果第三列大于100(passwd中的uid值),打印这个记录的第一列和第三列
- usbmuxd 113
- rtkit 499
- avahi-autoipd 170
- abrt 173
- nfsnobody 65534
- saslauth 498
- pulse 497
- 我们定义两个变量,分别判断两个值的大小
- [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"}}'
- no
- [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"}}'
- a=b
- [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"}}'
- ok
- 三元表达式的用法:
- [root@joker-6-01 zsfile]# awk 'BEGIN{a=1;b=2;a>b?a=3:b=3;print a,b}'
- 1 3
2、while循环
while(condition){statement;…}
do-while循环
do {statement;…}while(condition)
这种形式的循环表达的意思是,无论什么样的条件都会先执行一次循环,然后再判断while条件的真假。
- [root@joker-6-01 zsfile]# awk -v a=4 'BEGIN{while(a>0){ print a;a-=1 }}' #我没有想出一个应用场景啊,就用一个简单循环代替了。语法就是这么写
- 4
- 3
- 2
- 1
- d0-while用法
- [root@joker-6-01 zsfile]# awk 'BEGIN{total=0;i=0;do{total+=i;i++}while(i<=100);print total}' #计算前1-100的和
- 5050
3、for循环
for(expr1;expr2;expr3) {statement;…}
for(variable assignment;condition;iteration process){for-body}
- 两种语法:1、for i in array #这种方法,待会写了数组再谈
- 2、for( i=x;i<=100;i++)
- [root@newhostname zsfile]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /boot/grub2/grub.cfg #遍历一个文件
- linux16 7
- /vmlinuz-3.10.0-693.el7.x86_64 30
- root=/dev/mapper/centos_joker--7--01-root 41
- ro 2
- rd.lvm.lv=centos_joker-7-01/root 32
- rd.lvm.lv=centos_joker-7-01/swap 32
- rhgb 4
- quiet 5
- linux16 7
- /vmlinuz-0-rescue-77b790ce63d24178bd4d95027a1bd2e9 50
- root=/dev/mapper/centos_joker--7--01-root 41
- ro 2
- rd.lvm.lv=centos_joker-7-01/root 32
- rd.lvm.lv=centos_joker-7-01/swap 32
- rhgb 4
- 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自身循环)
- [root@newhostname zsfile]# awk -F: '{if($3==0) next; print $1,$3}' /etc/passwd | head -5 #打印非root用户
- bin 1
- daemon 2
- adm 3
- lp 4
- sync 5
这些控制语句是不是很眼熟,不论是什么语言都会有这些,只不过是表达形式的不同而已,原理都是一样的。
5、数组
awk的数组也分有序数组和关联数组两种
如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
- awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}' #定义一个数组,并打印
- 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,…
- [root@newhostname zsfile]# awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }' #输出10个100以内的随机数
- 52
- 68
- 13
- 38
- 95
- 28
- 59
- 45
- 84
- 19
- [root@newhostname zsfile]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$1)' #查找替换全部的:为-
- 2008-08-08 08:08:08
- [root@newhostname zsfile]# echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)' #查找替换第一个:为-
- 2008-08:08 08:08:08
- [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
- 0.0.0.0 4
- 172.18.101.180 1
7、awk函数
格式:
function name ( parameter, parameter, … ) {
statements
return expression
}
和其他语言的格式基本相同,用法也差不多,这里不多说了。
8、awk中调用shell命令,可以使用system()函数
- [root@newhostname zsfile]# awk BEGIN'{system("hostname") }'
- newhostname
四、最后了,我们现在再说这种用法 :awk [options] -f ‘a program file’ file …
其实很简单就是讲awk的语句存到文件内,然后使用 awk -f来调用,就像shell调用shell脚本一样
- [root@newhostname zsfile]# cat test_awk.awk
- #! /usr/bin/awk
- {if($3>=1000)print $1,$3}
- [root@newhostname zsfile]# awk -f test_awk.awk /etc/passwd
- systemd-network:x:192:192:systemd Management:/:/sbin/nologin
- dbus:x:81:81:System bus:/:/sbin/nologin
- polkitd:x:999:997:User polkitd:/:/sbin/nologin
- colord:x:998:996:User colord:/var/lib/colord:/sbin/nologin
- libstoragemgmt:x:997:994:daemon for
- pulse:x:171:171:PulseAudio Daemon:/var/run/pulse:/sbin/nologin
- tss:x:59:59:Account by
- geoclue:x:994:989:User geoclue:/var/lib/geoclue:/sbin/nologin
- rpcuser:x:29:29:RPC User:/var/lib/nfs:/sbin/nologin
- nfsnobody:x:65534:65534:Anonymous User:/var/lib/nfs:/sbin/nologin
- sssd:x:993:988:User sssd:/:/sbin/nologin
输出一个文件内最大长度字段的长度,和这个字段的值
- [root@newhostname shell]# cat longest_field.sh
- #!/usr/bin/env awk -f
- #
- #********************************************************************
- #encoding -*-utf8-*-
- #Author: zhangshang
- #Date: 2018-01-04
- #URL: http://blog.vservices.top/myblog
- #QQ Numbers: 765030447
- #********************************************************************
- BEGIN {
- max=0
- }
- {
- split($0,field_record,FS);
- for(i in field_record)
- {if(length(field_record[i])>max){
- max=length(field_record[i]);max_field=field_record[i]}
- }
- }
- END{
- print max_field,max
- }
- #max=i;
- [root@newhostname shell]# cat ~/112233 #查看文本
- aaa:asdf:ddddddddd
- z:asdfasdfasd:asdfasdfasdfasdf:asdfz:ddd
- cccccccccccccccccc:eeeeeee:1111111:
- [root@newhostname shell]# awk -F: -f longest_field.sh ~/112233 #awk调用脚本
- 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,显示源输出的指定列:
- [root@newhostname /]# df | grep /dev/sd #先查看一下源标准输出
- /dev/sda1 1038336 162080 876256 16% /boot
- /dev/sdb3 3135488 135364 3000124 5% /mnt/xfs
- /dev/sdb2 3030800 9236 2847896 1% /mnt/ext4
- [root@newhostname /]# df | grep /sd | awk '{print $1"==="$5}'
- /dev/sda1===16%
- /dev/sdb3===5%
- /dev/sdb2===1%
- #$1为输出的第一列,$5为第5列,awk的默认字符是空表字符, 两列中间的等号为加入的字符串“===”
实例2,使用awk的内置变量:
- [root@newhostname /]# awk -v FS=':' '{print $1,FS,$3}' /etc/passwd | head -5 #我们使用内置变量FS来作为分隔符
- root : 0
- bin : 1
- daemon : 2
- adm : 3
- lp : 4
- [root@newhostname /]# awk -F: '{print $1,FS,$3}' /etc/passwd | head -5 #我们使用-F option来指定分隔符
- root : 0
- bin : 1
- daemon : 2
- adm : 3
- lp : 4
- #由上面两个结果来看,其意义是一样的, 可以使用 -v 直接声明字段的分隔符,也可以用-F来指定。而在action内,变量是可以直接被调用的 ,注意,action内不要看走眼,如果是字符串的话,需要加“”“,直接输入的字符会当做变量来处理。
OFS变量的作用:
- [root@newhostname /]# awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd | head -5 #OFS输出字段分隔符,默认为空白,这里我们指定为“:”
- root:0:/bin/bash
- bin:1:/sbin/nologin
- daemon:2:/sbin/nologin
- adm:3:/sbin/nologin
- lp:4:/sbin/nologin
- [root@newhostname /]# awk -v FS=':' '{print $1,$3,$7}' /etc/passwd | head -5 #我们不指定OFS两段命令一对比,很明显,下面输出的使用的默认输出分隔符为空白。
- root 0 /bin/bash
- bin 1 /sbin/nologin
- daemon 2 /sbin/nologin
- adm 3 /sbin/nologin
- lp 4 /sbin/nologin
RS、ORS变量的应用:
- [root@newhostname zsfile]# cat 123.txt #文件的原输出
- dddd:112233:1000:1000 /home/bash:/bin/bash
- [root@newhostname zsfile]# awk -v RS=':' '{print }' ./123.txt #定义RS变更记录分隔符(默认的分隔符是换行符)
- dddd
- 112233
- 1000
- 1000 /home/bash
- /bin/bash
- [root@newhostname zsfile]# awk -v RS=':' -v ORS='|-|' '{print }' ./123.txt #我们定义ORS来改变输出的分隔符
- dddd|-|112233|-|1000|-|1000 /home/bash|-|/bin/bash
- |-|[root@newhostname zsfile]#
RS的意义是改变处理文本之前的记录分隔符,当处理完记录之后,输出记录分隔符(ORS)如果未定义,则还是现实原来默认的记录分隔符去显示,即默认的换行符。
实例3,NF字段数量,NR行号变量,FNR分文件行号变量,FILENAME当前的文件名,ARGC命令行参数的个数
- [root@newhostname zsfile]# vim 1111
- [root@newhostname zsfile]# cat 1111
- aa bb cc dd ee
- 11 22 33 44 55
- 33 22 11 ss 44
- [root@newhostname zsfile]# awk '{print NR,NF}' 1111 #NR表示第几行,NF为列的总数
- 1 5
- 2 5
- 3 5
- [root@newhostname zsfile]# awk '{print NR,$NF}' 1111 #$NF表示最后一列
- 1 ee
- 2 55
- 3 44
- [root@newhostname zsfile]# awk '{print NR,$NF}' 1111 123.txt #如果使用awk同时对多个文件进行处理,那么使用NR,最后的出列结果会合并成1个,而不会按文件分开,如果要按文件分开,要是用FNR
- 1 ee
- 2 55
- 3 44
- 4 /home/bash:/bin/bash
- [root@newhostname zsfile]# awk '{print FNR,$NF}' 1111 123.txt #使用FNR按文件分开
- 1 ee
- 2 55
- 3 44
- 1 /home/bash:/bin/bash
- [root@newhostname zsfile]# awk '{print FILENAME,FNR,$NF}' 1111 123.txt #FILENAME 在输出列输出文件的名字
- 1111 1 ee
- 1111 2 55
- 1111 3 44
- 123.txt 1 /home/bash:/bin/bash
- [root@newhostname zsfile]# awk '{print ARGC}' 1111 #awk 表示一个参数 1111表示一个参数
- 2
- 2
- 2
- [root@newhostname zsfile]# awk '{print ARGC}' 1111 123.txt #awk表示1个参数,1111表示一个参数,123.txt表示一个参数,所以输出结果为“3”
- 3
- 3
- 3
- 3
- [root@newhostname zsfile]# awk 'BEGIN {print ARGC}' /etc/fstab /etc/inittab
- 3
变量是可以在action内定义的,但是不利于写shell脚本,因为一般action都是有单引号引起来的,在shell内单引号是强引用,无法很好地使用shell变量(是shell变量非awk变量)
printf的用法(格式化字符串输出,比print更强大的输出方式,printf实际上也是一个linux命令):
printf的格式和特性:printf “FORMAT”, item1, item2, …
(1) 必须指定FORMAT
(2) 不会自动换行,需要显式给出换行控制符,\n
(3) FORMAT中需要分别为后面每个item指定格式符
printf的格式符:
%c: 显示字符的ASCII码
%d, %i: 显示十进制整数
%e, %E:显示科学计数法数值
%f:显示为浮点数
%g, %G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数
%%: 显示%自身
修饰符:
#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f
-: 左对齐(默认右对齐,对字符串你操作) %-15s
+:显示数值的正负符号 %+d
下面我们来用printf来举例:
printf字符串的格式化
- [root@joker-6-01 ~]# awk -F: '{printf "%s - ",$1}' /etc/passwd #printf 后面的%s代表的是$1,在这里$1不仅可以是列,还可以是变量、字符串
- 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 ~]#
- 由以上输出我们可以看出,printf是不会换行的,如果要换行 printf引号呢最后要添加\n
- [root@joker-6-01 ~]# awk -F: '{printf "%s - \n",$1}' /etc/passwd | head -5 #添加\n,(因为条目太多,所以在这里我把条目限定在了5行,后面的示例也都这样操作)
- root -
- bin -
- daemon -
- adm -
- lp -
- 每一条记录执行完都会换行
printf的使用修饰符
- [root@joker-6-01 ~]# awk -F: '{printf "Username:%s,UID:%d\n",$1,$3}' /etc/passwd | head -5
- Username:root,UID:0
- Username:bin,UID:1
- Username:daemon,UID:2
- Username:adm,UID:3
- Username:lp,UID:4
- 在这里我们使用字符串的格式化输出,但是输出结果并不直观,下面我们可以使用修饰符进行分割。
- [root@joker-6-01 ~]# awk -F: '{printf "Username:%-20sUID:%d\n",$1,$3}' /etc/passwd | head -5 #%-20s :20表示最大长度,“-”表示左对齐
- Username:root UID:0
- Username:bin UID:1
- Username:daemon UID:2
- Username:adm UID:3
- Username:lp UID:4
- 输出的结果很明显
- [root@joker-6-01 ~]# awk -F: '{printf "Username:%20sUID:%d\n",$1,$3}' /etc/passwd | head -5 #不加“-”的表示默认右对齐,在这里只是一个示例,没有任何意义
- Username: rootUID:0
- Username: binUID:1
- Username: daemonUID:2
- Username: admUID:3
- Username: lpUID:4
- 在这种环境下,使用右对齐显示不是我们要的,在这里我只是想标清楚,什么是左对齐,什么是右对齐
- 接下来我们示范一下浮点数的表示方法
- [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%f\n",3.1234}'
- 3.123400
- [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%f\n",3.1}'
- 3.100000
- 使用%f默认会甩出6位的小数位,那么我们使用修饰符来限定位数,关于BEGIN,在这里的意思是只执行一遍指令,并且不需要读取文件,BEGIN的真正含义是在读取文件之前执行的操作,我们在这里先不管,后面会讲解
- [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%8.3f\n",3.1}' #8代表整数字符的宽度;.3代表小数的位数
- 3.100
- [root@joker-6-01 ~]# awk -F: 'BEGIN{printf"%08.3f\n",3.1}' #08指如果整数位不足8位用0来代表空白
- 0003.100
- 浮点数的修饰一般我们做普通运维用不到,一般用的比较多的还是%s %d这两个
AWK的运算符:在action内执行
算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x: 转换为负数
+x: 转换为数值
字符串操作符:没有符号的操作符,字符串连接
赋值操作符:
=, +=, -=, *=, /=, %=, ^=
++, —
比较操作符:
==, !=, >, >=, <, <=
模式匹配符:
~:左边是否和右边匹配包含 !~:是否不匹配
逻辑操作符:
与&&,或||,非!
不多说了,直接举例:
- [root@joker-6-01 ~]# awk -F: '$0 ~ /root/{print $1}' /etc/passwd # “~” 匹配运算符
- root
- operator
- 大括号前面的这一部分,代表的就是最开始所说的“pattern”,这部分的的实际作用就是用来匹配指定记录。上面的含义就是 $0(整条记录)内是否有匹配root的记录,我们在这里使用的“root”是一个实际的字符串,在这里我们也可以使用正则表达式来匹配,我们使用/regex/的形式来表示匹配,我们来做个演示。
- [root@joker-6-01 ~]# cat /etc/passwd | tail -10 #现实passwd的后10行,我们将对这段字符进行操作
- gdm:x:42:42::/var/lib/gdm:/sbin/nologin
- pulse:x:497:496:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
- sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
- tcpdump:x:72:72::/:/sbin/nologin
- ee:x:500:500:dd,ff,aa,qwe:/home/ee:/bin/bash
- rr:x:501:502::/home/rr:/bin/bash
- wang:x:1010:1010::/app/wangs:/bin/bash
- wang1:x:1014:1011::/home/wang1:/bin/bash
- wang2:x:1012:1012::/home/wang2:/bin/bash
- wang3:x:1013:1013::/home/wang3:/bin/bash
- [root@joker-6-01 ~]#cat /etc/passwd | tail -10| awk '$0 ~ /^t.+n$/{print $0}'
- tcpdump:x:72:72::/:/sbin/nologin
- “/^t.+n$/” 代表的开头是“t”结尾为“n”的记录。
- 我们再来做一个不配“t”结尾为“n”的记录的示例:
- [root@joker-6-01 ~]# cat /etc/passwd | tail -10 | awk '$0 !~ /^t.+n$/{print $0}' # “!~” 表示不匹配,也就是说,不匹配的记录,awk认为是我们需要的数据
- gdm:x:42:42::/var/lib/gdm:/sbin/nologin
- pulse:x:497:496:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
- sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
- ee:x:500:500:dd,ff,aa,qwe:/home/ee:/bin/bash
- rr:x:501:502::/home/rr:/bin/bash
- wang:x:1010:1010::/app/wangs:/bin/bash
- wang1:x:1014:1011::/home/wang1:/bin/bash
- wang2:x:1012:1012::/home/wang2:/bin/bash
- wang3:x:1013:1013::/home/wang3:/bin/bash
- 我们再action内做算数运算
- [root@joker-6-01 ~]# awk 'BEGIN{print 2+2}'
- 4
- [root@joker-6-01 ~]# awk 'BEGIN{print 2*3}'
- 6
- [root@joker-6-01 ~]# awk 'BEGIN{print 2%3}'
- 2
- [root@joker-6-01 ~]# awk 'BEGIN{print 2**3}'
- 8
- 然后我这里有个坑:
- [root@joker-6-01 ~]# awk 'BEGIN{i=0;print ++i,i}' #限制性i+1 然后在输出i
- 1 1
- [root@joker-6-01 ~]# awk 'BEGIN{i=0;print i++,i}' #先输出 i 然后再执行 i+1,所以这两个结果不同
- 0 1
- [root@joker-6-01 zsfile]# awk -F: '$3 == 0' /etc/passwd #以:为分隔符,如果第三列为0,那么打印这一样,省略action则表示打印整条记录
- root:x:0:0:root:/root:/bin/bash
- 逻辑运算符的使用方法
- [root@joker-6-01 zsfile]# awk -F: '$3 >=0 && $3<=100{print $1}' /etc/passwd #uid大于等于0,小于等于100的记录,打印第一列
- root
- bin
- daemon
- adm
- lp
- sync
- shutdown
- halt
- uucp
- operator
- games
- gopher
- ftp
- nobody
- dbus
- rpc
- vcsa
- rpcuser
- haldaemon
- ntp
- apache
- postfix
- gdm
- sshd
- tcpdump
- [root@joker-6-01 zsfile]# awk -F: '!($3==0) && NR==3 {print $1}' /etc/passwd #这句表达的意思:取第三行,如果第三列不等于0,就打印该行,否则不操作。
- daemon
2、awk [options] ‘BEGIN{ action;… } pattern{ action;… } END{action;… }’ file …的详细使用方法
BEGIN/END模式
BEGIN{}: 仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
示例:
- [root@joker-6-01 zsfile]# awk -F : 'BEGIN {printf "USER %-16sUSERID\n",""}/^(t|p)/ {printf "%-20s %s\n",$1,$3}END{printf "end%-18sfile\n",""}' /etc/passwd
- 执行结果:
- USER USERID #BEGIN开始打印一行
- postfix 89
- pulse 497
- tcpdump 72
- end file #END执行完后打印
- 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
- [root@joker-6-01 zsfile]# awk -F: '{if($3 >=100)print $1,$3}' /etc/passwd #判断如果第三列大于100(passwd中的uid值),打印这个记录的第一列和第三列
- usbmuxd 113
- rtkit 499
- avahi-autoipd 170
- abrt 173
- nfsnobody 65534
- saslauth 498
- pulse 497
- 我们定义两个变量,分别判断两个值的大小
- [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"}}'
- no
- [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"}}'
- a=b
- [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"}}'
- ok
- 三元表达式的用法:
- [root@joker-6-01 zsfile]# awk 'BEGIN{a=1;b=2;a>b?a=3:b=3;print a,b}'
- 1 3
2、while循环
while(condition){statement;…}
do-while循环
do {statement;…}while(condition)
这种形式的循环表达的意思是,无论什么样的条件都会先执行一次循环,然后再判断while条件的真假。
- [root@joker-6-01 zsfile]# awk -v a=4 'BEGIN{while(a>0){ print a;a-=1 }}' #我没有想出一个应用场景啊,就用一个简单循环代替了。语法就是这么写
- 4
- 3
- 2
- 1
- d0-while用法
- [root@joker-6-01 zsfile]# awk 'BEGIN{total=0;i=0;do{total+=i;i++}while(i<=100);print total}' #计算前1-100的和
- 5050
3、for循环
for(expr1;expr2;expr3) {statement;…}
for(variable assignment;condition;iteration process){for-body}
- 两种语法:1、for i in array #这种方法,待会写了数组再谈
- 2、for( i=x;i<=100;i++)
- [root@newhostname zsfile]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /boot/grub2/grub.cfg #遍历一个文件
- linux16 7
- /vmlinuz-3.10.0-693.el7.x86_64 30
- root=/dev/mapper/centos_joker--7--01-root 41
- ro 2
- rd.lvm.lv=centos_joker-7-01/root 32
- rd.lvm.lv=centos_joker-7-01/swap 32
- rhgb 4
- quiet 5
- linux16 7
- /vmlinuz-0-rescue-77b790ce63d24178bd4d95027a1bd2e9 50
- root=/dev/mapper/centos_joker--7--01-root 41
- ro 2
- rd.lvm.lv=centos_joker-7-01/root 32
- rd.lvm.lv=centos_joker-7-01/swap 32
- rhgb 4
- 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自身循环)
- [root@newhostname zsfile]# awk -F: '{if($3==0) next; print $1,$3}' /etc/passwd | head -5 #打印非root用户
- bin 1
- daemon 2
- adm 3
- lp 4
- sync 5
这些控制语句是不是很眼熟,不论是什么语言都会有这些,只不过是表达形式的不同而已,原理都是一样的。
5、数组
awk的数组也分有序数组和关联数组两种
如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
- awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}' #定义一个数组,并打印
- 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,…
- [root@newhostname zsfile]# awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }' #输出10个100以内的随机数
- 52
- 68
- 13
- 38
- 95
- 28
- 59
- 45
- 84
- 19
- [root@newhostname zsfile]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$1)' #查找替换全部的:为-
- 2008-08-08 08:08:08
- [root@newhostname zsfile]# echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)' #查找替换第一个:为-
- 2008-08:08 08:08:08
- [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
- 0.0.0.0 4
- 172.18.101.180 1
7、awk函数
格式:
function name ( parameter, parameter, … ) {
statements
return expression
}
和其他语言的格式基本相同,用法也差不多,这里不多说了。
8、awk中调用shell命令,可以使用system()函数
- [root@newhostname zsfile]# awk BEGIN'{system("hostname") }'
- newhostname
四、最后了,我们现在再说这种用法 :awk [options] -f ‘a program file’ file …
其实很简单就是讲awk的语句存到文件内,然后使用 awk -f来调用,就像shell调用shell脚本一样
- [root@newhostname zsfile]# cat test_awk.awk
- #! /usr/bin/awk
- {if($3>=1000)print $1,$3}
- [root@newhostname zsfile]# awk -f test_awk.awk /etc/passwd
- systemd-network:x:192:192:systemd Management:/:/sbin/nologin
- dbus:x:81:81:System bus:/:/sbin/nologin
- polkitd:x:999:997:User polkitd:/:/sbin/nologin
- colord:x:998:996:User colord:/var/lib/colord:/sbin/nologin
- libstoragemgmt:x:997:994:daemon for
- pulse:x:171:171:PulseAudio Daemon:/var/run/pulse:/sbin/nologin
- tss:x:59:59:Account by
- geoclue:x:994:989:User geoclue:/var/lib/geoclue:/sbin/nologin
- rpcuser:x:29:29:RPC User:/var/lib/nfs:/sbin/nologin
- nfsnobody:x:65534:65534:Anonymous User:/var/lib/nfs:/sbin/nologin
- sssd:x:993:988:User sssd:/:/sbin/nologin
输出一个文件内最大长度字段的长度,和这个字段的值
- [root@newhostname shell]# cat longest_field.sh
- #!/usr/bin/env awk -f
- #
- #********************************************************************
- #encoding -*-utf8-*-
- #Author: zhangshang
- #Date: 2018-01-04
- #URL: http://blog.vservices.top/myblog
- #QQ Numbers: 765030447
- #********************************************************************
- BEGIN {
- max=0
- }
- {
- split($0,field_record,FS);
- for(i in field_record)
- {if(length(field_record[i])>max){
- max=length(field_record[i]);max_field=field_record[i]}
- }
- }
- END{
- print max_field,max
- }
- #max=i;
- [root@newhostname shell]# cat ~/112233 #查看文本
- aaa:asdf:ddddddddd
- z:asdfasdfasd:asdfasdfasdfasdf:asdfz:ddd
- cccccccccccccccccc:eeeeeee:1111111:
- [root@newhostname shell]# awk -F: -f longest_field.sh ~/112233 #awk调用脚本
- cccccccccccccccccc 18