awk在CentOS操作系统中是一个软链接,链接到gawk程序上的。awk主要是对文件的行进行操作,将一行按照指定的方式进行切割。
一、awk工作机制
awk在处理文本流时,每一次会读取文本流中的一行并对这一行按指定的分隔符进行分隔,分隔后可以对每一个字段进行处理,其中输入的分隔符可以和输出的分隔符不一样,这些都是通过awk内置的变量来处理的。
二、awk命令运用
格式:awk [OPTIONS] ‘program‘ FILE1 FILE2 ...
2.1 print
用法:print item1,item2,….
示例1:输出/etc/passwd文件中的第1个字段和第3个字段的值
[[email protected] ~]# awk -F: ‘{print $1,$3}‘/etc/passwd root 0 bin 1 daemon 2 adm 3
根据输出结果进行分析:
(1)-F:用于指明输入字段的分隔符
(2)每个item之间用逗号分隔,输出时的分隔符为空白字符;
(3)如果print在输出时省略了item,将会输出整行的内容
示例2:根据上示例的要求,进行以“Name:root,UID:0”的格式输出
[[email protected] ~]# awk -F: ‘{print"Name:"$1,",UID:"$3}‘ /etc/passwd Name:root ,UID:0 Name:bin ,UID:1 Name:daemon ,UID:2
根据输出结果进行分析:
(1)在各item中以“”引号的内容将会原样的输出
(2)数值会被隐式转换为字符串进行输出
2.2 awk变量
awk的变量有内建变量和自定义的变量,内建变量是awk事先就已经定义好了,直接使用变量名就可以了,自定义变量根据情况的需求进行定义。
2.2.1 自定义变量
格式:-v VAR_NAME=VALUE
示例:[[email protected] ~]# awk -v file="abc""{print file}" /etc/passwd abc abc abc
根据输出结果进行分析:
(1)-v用于自定义变量,变量名区别大小写,遵循变量的定义
(2)显示变量的值直接写上变量名
(3)示例中将输出多次,次数是根据/etc/passwd的行数来决定的
2.2.2 内建变量
变量名 | 说明 |
FS | 输入字段分隔符,默认为空白; |
RS | 输入时的行分隔符,默认为换行符; |
OFS | 输出时的字段分隔符,默认为空白字符; |
ORS | 输出时的行分隔符,默认为换行符; |
NF | 当前行的字段数; |
NR | 行数;命令后跟的所有文件将统一计数; |
FNR | 行数,多个文件时,各文件单独计数; |
FILENAME | 当前正被awk读取的文件的文件名; |
ARGC | awk命令行中的参数的个数; |
ARGV | 数组,保存了命令行参数本身; |
示例1:显示/etc/passwd文件中以“:”和“/”分隔符的第1个字段和第7个字段,原文件如下:
[[email protected] ~]# cat /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
[[email protected] ~]# awk -v FS="[:/]"‘{print $1,$7}‘ /etc/passwd root root bin bin daemon sbin
根据输出结果进行分析:
(1)-v:对变量进行赋值,包含内建变量和自定义变量;
(2)FS是awk的内建变量,表示指定字符之间的分隔符;
(3)FS的值要用双引号引起来,如果要指定多个分隔直接写在“[]”中即可。
示例2:测试文件如下,以“,”为行结束符,输出整行的内容,接着输出第1字段、第3字段:
[[email protected] ~]# cat awk.txt how are you , how old are you ? how old your , Yes are you ? [[email protected] ~]# awk -v RS=","‘{print $0}‘ awk.txt how are you howold are you ? how old your Yesare you ? [[email protected] ~]# awk -v FS=" " -v RS="," ‘{print $1,$3}‘ awk.txt how you how are Yes you
根据输出结果进行分析:
(1)RS改变了行结束符,默认的行结束符可以使用cat -A awk.txt查看。
(2)-v选项可以使用多次,每定义一个变量的值,要使用一次“-v”选项。
示例3:根据/etc/passwd文件中输出第1字段和第3字段,格式为“root:0”,原文件如下:
[[email protected] ~]# cat /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
方法1: [[email protected] ~]# awk -F: -v OFS=":" ‘{print $1,$3}‘/etc/passwd root:0 bin:1 daemon:2 方法2: [[email protected] ~]# awk -F: ‘{print $1":"$3}‘ /etc/passwd root:0 bin:1 daemon:2
根据输出结果进行分析:
(1)-v OFS=”:”用于定义输出字段之间的分隔符,默认为空白字符
(2)方法2中的 pirnt $1”:”$3,中的双引号中的内容会原样的输出,这就是字符串之间的连接
示例4:将示例3中的输出结果以“,”会换行符。
[[email protected] ~]# awk -F: -vORS="," ‘{print $1":"$3}‘ /etc/passwd root:0,bin:1,daemon:2,[[email protected] ~]#
根据输出结果进行分析:
(1)ORS更改默认的换行符将以指定符号输出
示例5:根据如下文件内容,输出字段的个数,并显示最后一个字段的内容
[[email protected] ~]# cat awk.txt how are you , how old are you ? how old your , Yes are you ? [[email protected] ~]# awk ‘{print NF,$NF}‘awk.txt 9 ? 8 ?
根据输出结果进行分析:
(1)NF使用显示被分隔符分隔后的字段个数。
(2)$后面跟上一个数字用于显示指定字段的内容,而NF是一个数字,替换后就是显示最后一个字段。
示例6:显示awk.txt和/etc/passwd文件行号
[[email protected] ~]# awk ‘{print NR,$0}‘awk.txt /etc/passwd 1 how are you , how old are you ? 2 how old your , Yes are you ? 3 root:x:0:0:root:/root:/bin/bash 4 bin:x:1:1:bin:/bin:/sbin/nologin 5 daemon:x:2:2:daemon:/sbin:/sbin/nologin [[email protected] ~]# awk ‘{print FNR,$0}‘awk.txt /etc/passwd 1 how are you , how old are you ? 2 how old your , Yes are you ? 1 root:x:0:0:root:/root:/bin/bash 2 bin:x:1:1:bin:/bin:/sbin/nologin 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
根据输出结果进行分析:
(1)awk后可以跟多个文件
(2)NR变量在对多个文件显示行号时,后一个文件的行号是接着前一个文件的行号继续增加显示的
(3)FNR变量对多个文件是分别进行显示行号
示例7:显示awk当前正在处理的文件名
[[email protected] ~]# awk ‘{print FNR,FILENAME}‘awk.txt /etc/passwd 1 awk.txt 2 awk.txt 1 /etc/passwd 2 /etc/passwd 3 /etc/passwd
示例8:根据示例7显示awk的参数个数及第2个参数的值
[[email protected] ~]# awk ‘{printFNR,FILENAME,ARGC,ARGV[1]}‘ awk.txt /etc/passwd 1 awk.txt 3 awk.txt 2 awk.txt 3 awk.txt 1 /etc/passwd 3 awk.txt 2 /etc/passwd 3 awk.txt 3 /etc/passwd 3 awk.txt
根据输出结果进行分析:
(1)ARGC用于保存当前awk参数的个数
(2)ARGV是一个数组,保存的是当前数组每个参数的值,数组的Index号是从0开始编号的,ARGV[0]存放的是awk, ARGV[1]存放的是awk.txt, ARGV[2]存放的是/etc/passwd,ARGV[3]存放的是NULL。
2.3 printf
printf用于格式化输出,此风格类似于C语言中的格式化输出信息,可以根据定义在指定的位置显示字段信息及保留小数点后指定的位数等 。
格式:printf FORMAT,item1,item2,...
类型 | 符号 | 说明 |
格式符 | %c | 显示字符的ASCII码; |
%d,%i | 显示为十进制整数; | |
%e,%E | 科学计数法显示数值; | |
%f | 显示为浮点数; | |
%g,%G | 以科学计数法或浮点数格式显示数值; | |
%s | 显示为字符串; | |
%u | 显示无符号整数; | |
%% | 显示%符号自身; | |
修饰符 | #[.#] | 左边的#指用于指定显示宽度;右边的#指显示精度; |
+ | 显示数值符号 | |
- | 左对齐,默认为右对齐 |
注意:
(1) 必须提供FORMAT;
(2) 与print语句不同,printf不会自动换行,需要显式指定换行符:\n
(3) FORMAT中需要分别为后面的每个item指定一个格式符,否则item则无法显示;
示例:将/etc/passwd文件进行格式化输出
[[email protected] ~]# awk -F: ‘{printf"%20s:%-10.5f:%s\n",$1,$3,$NF}‘ /etc/passwd root:0.00000 :/bin/bash bin:1.00000 :/sbin/nologin daemon:2.00000 :/sbin/nologin [[email protected] ~]# awk -F: ‘{printf"%20s:%10.5f:%s\n",$1,$3,$NF}‘ /etc/passwd root: 0.00000:/bin/bash bin: 1.00000:/sbin/nologin daemon: 2.00000:/sbin/nologin
根据输出结果进行分析:
(1)%20s:输出的是字符串,第1个字段的长度为20,awk默认是右对齐
(2)%10.5f:输出的是浮点型数值,长度是10,小点后面保留5位
(3)%-10.5f:其中的“-”表示左对齐
(4)\n:表示换行符
(5)FORMAT中除格式符和修饰符之外的其它符号或字符都将原样的输出
2.4 操作符
awk的操作符非常的丰富,包含算术操作符、字符操作符、赋值操作符、比较操作符、模式匹配操作符、逻辑操作符、条件表达式等。
类型 | 符号 | 说明 |
算术操作符 | x+y, x-y, x*y, x/y, x^y, x%y,-x,+x | 加、减、乘、除、次方、模,负值、转换为数值 |
赋值操作符 | =, +=, -=, *=, /=, %=,++, -- | 赋值、加后赋值、减后赋值、乘后赋值、除后赋值、取模后赋值、自增、自减 |
比较操作符 | >, >=, <, <=, ==, != | 大于、大于等于、小于、小于等于、等于、不等于 |
模式匹配操作符 |
~,!~ |
是否能由右侧指定的模式所匹配;是否不能由右侧指定模式所匹配; |
逻辑操作符 | &&,|| | 与运算、或运算 |
条件条件式 | selector?if-true-expression:if-false-expression | 条件表达式 |
示例1:显示/etc/passwd文件UID大于500的用户
[[email protected] ~]# awk -F: ‘$3>500{print$1,$3}‘ /etc/passwd nfsnobody 65534 testuser 1000 centos 1001 user1 1002 gentoo 1003
示例2:显示/etc/passwd文件中每行字段中包含有bash字符的行
[[email protected] ~]# awk -F:‘$0~"bash"{print $0}‘ /etc/passwd root:x:0:0:root:/root:/bin/bash bbs:x:496:493::/home/bbs:/bin/bash testuser:x:1000:500::/home/testuser:/bin/bash centos:x:1001:1001::/home/centos:/bin/bash user1:x:1002:1002:chrootuser:/home/user1:/bin/bash gentoo:x:1003:1003::/home/gentoo:/bin/bash nginx:x:495:492::/home/nginx:/bin/bash
示例3:判断用户UID是否大于等于500,格式化显示用户名信息
[[email protected] ~]# awk -F: ‘$3>=500?type="commonuser":type="system user"{printf "%20s:%s\n",$1,type }‘/etc/passwd ……………省略………………… testuser:common user centos:common user user1:common user gentoo:common user nginx:system user
根据输出结果进行分析:
(1)$3>=500?type="commonuser":type="system user":将/etc/passwd文件中以“:”为分隔符第3段值取出来,如果UID大于等于500把变量type赋值systemuser,否则就把变量type赋值system user.
(2)使用格式化显示用户名和type变量的值
2.5 PATTERN
在PATTERN中可以使用正则表达式,关系表达式,指定要处理的行范围等等 。
PATTERN | 说明 |
Empty | 空模式,匹配所有行; |
/Regular Expression/ | 仅将ACTION应用于能够被Regular Expression(正则表达式)所匹配到的行; |
relational expression | 关系表达式,即结果为“真”、“假”的表达式,或者其结果能类同于“真”或“假”的表达;一般来说,其结果为非0数值或非空字符串即可类同为“真”,否则,则类同为“假”; |
line ranges | 行范围,类似sed或vim中的地址定界方式; |
BEGIN | 在文件格式化操作开始之前事先执行的一次操作;通常用于输出表头或做出一个预处理操作; |
END | 在文件格式操作完成之后,命令退出之前执行的一次操作;通常用于输出表尾或做出清理操作; |
示例1:在/etc/passwd文件中显示以bash结尾的行
[[email protected] ~]# awk -F: ‘/bash$/{print$0}‘ /etc/passwd root:x:0:0:root:/root:/bin/bash bbs:x:496:493::/home/bbs:/bin/bash testuser:x:1000:500::/home/testuser:/bin/bash centos:x:1001:1001::/home/centos:/bin/bash user1:x:1002:1002:chrootuser:/home/user1:/bin/bash gentoo:x:1003:1003::/home/gentoo:/bin/bash nginx:x:495:492::/home/nginx:/bin/bash
示例2:在/etc/passwd文件中显示UID大于500的用户名
[[email protected] ~]# awk -F: ‘$3>500{print$1}‘ /etc/passwd nfsnobody testuser centos user1 gentoo
示例3:统计/etc/passwd文件中所有UID的和
[[email protected] ~]# awk ‘BEGIN{FS=":";sum=0}{sum+=$3}END{print sum}‘ /etc/passwd 73318
根据输出结果进行分析:
(1)BEGIN{FS=":";sum=0}:表示在awk在对行处理之前执行的动作,FS是指定字段的分隔符,sum是自定义的一个变量,用于累加所有UID的和
(2){sum+=$3}:就是在对每一行进行操作,这里没有使用print输出信息,sum=sum+$3;
(3)END{print sum}:awk对文件中所有行处理完之后在执行END的语句
示例4:格式化输出/etc/passwd文件中用户和UID
[[email protected] ~]# awk -F: ‘BEGIN {printf"%15s:%-s\n","User","UID";print"================================="}{printf"%15s:%-s\n",$1,$3}END{print"================================";printf "%20s\n","ENDof file"}‘ /etc/passwd User:UID ================================= root:0 bin:1 daemon:2 adm:3 lp:4 sync:5 …………………省略……………… user1:1002 gentoo:1003 nginx:495 ================================ END of file
2.6 控制语句
在awk控制语句中有if、while、do、for、switch、break、contiune、next等
2.6.1 if-else语句
格式:if (condition) {statements} [else{statements}]
示例1:在/etc/passwd文件中显示UID大于500的用户名
[[email protected] ~]# awk -F:‘{if($3>500){print $1,$3}}‘ /etc/passwd nfsnobody 65534 testuser 1000 centos 1001 user1 1002 gentoo 1003
示例2:判断/etc/inittab的字段数大于6的,以空格分隔的
[[email protected] ~]# awk ‘{if (NF>6) {printNF,$0}}‘ /etc/inittab 11 # inittab is only used by upstart forthe default runlevel. 12 # ADDING OTHER CONFIGURATION HERE WILLHAVE NO EFFECT ON YOUR SYSTEM. 7 # System initialization is started by/etc/init/rcS.conf 7 # Individual runlevels are started by/etc/init/rc.conf 9 # Terminal gettys are handled by/etc/init/tty.conf and /etc/init/serial.conf, 12 # For information on how to writeupstart event handlers, or how 8 # upstart works, see init(5), init(8),and initctl(8). 7 # Default runlevel. The runlevels usedare: 10 # 0 - halt (Do NOT set initdefault to this) 16 # 2 - Multiuser, without NFS (The same as 3, if you do not havenetworking) 10 # 6 - reboot (Do NOT set initdefault to this)
2.6.2 while循环
格式:while (condition) {statements}
示例:显示字段字符数大于10的字符
[[email protected] ~]# awk ‘{i=1;while(i<NF){if (length($i)>10) printf "%20s:%d\n",$i,length($i);i++}}‘/etc/inittab CONFIGURATION:13 initialization:14 Ctrl-Alt-Delete:15 /etc/init/tty.conf:18 configuration:13 information:11 initdefault:11 initdefault:11
根据输出结果进行分析:
(1)while用于在当前行的种字段之间进行循环。
(2)length()是awk的内置变量,用于测试字符在长度的
2.6.3 for循环
格式:for (expr1;expr2;expr3) {statements}
示例:显示/etc/inittab文件中以空格为分隔符,显示每个字段的长度
[[email protected] ~]# awk ‘{for(i=1;i<=NF;i++) {printf "%20s:%d\n",$i,length($i)}}‘ /etc/inittab #:1 inittab:7 is:2 only:4 used:4 by:2
2.6.4 bread 和countinue
break [n]:退出当前循环,n是一个数字,用于指定退出几层循环;
continue:提前结束本轮循环而进入下一轮;
示例:显示/etc/passwd每个字段的字符数小于10的,只要遇到大于10的就不在判断后面的字段的字符数
[[email protected] ~]# awk -F:‘{for(i=1;i<=NF;i++){if(length($i)>10){break}else {printlength($i),$i}}}‘ /etc/passwd 4 root 1 x 1 0 1 0 4 root 5 /root 9 /bin/bash 3 bin 1 x 1 1 1 1
2.6.5 next
next用于提前结束对本行文本的处理,而提前进入下一行的处理操作;
示例:显示/etc/passwd中UID是奇数的用户名和UID
[[email protected] ~]# awk -F: ‘{if($3%2==0)next;print $1,$3}‘ /etc/passwd bin 1 adm 3 sync 5 halt 7 operator 11 gopher 13 nobody 99
2.7 数组
格式:array[index-expression]
其中index-expression可以是任意字符,如果某数组元素事先不存在,则在引用时,awk会自动创建元素并将其值初始化为空串,awk的数组下标是从1开始编号的。
如果要遍历数组中的元素,则要使用for (var_name in array)
示例:统计当前系统上所有tcp连接的各种状态的个数;
[[email protected] ~]# netstat -tan|awk ‘/^tcp/{count[$NF]++}END{for(i incount){print i,count[i]}}‘ TIME_WAIT 4000 ESTABLISHED 2 LISTEN 8
示例:统计指定的web访问日志中各ip的资源访问次数:
[[email protected] ~]# awk ‘{ip[$1]++}END{for (iin ip){print i,ip[i]}}‘ /var/log/httpd/access_log 172.16.9.35 4016 172.16.9.7 186 172.16.9.9 153
2.8 函数
在awk中函数有内建函数和用户自定义函数两种。
2.8.1 内建函数
函数名 | 说明 |
rand() | 返回0至1之间的一个随机数; |
length([s]) | 返回指定的字符串的长度; |
sub(r,s[,t]) | 基于r所表示的模式来匹配字符串t中的内容,将其第一次被匹配到的内容替换为s所表示的字符串; |
gsub(r,s[,t]) | 基于r所表示的模式来匹配字符串t中的内容,将其所有被匹配到的内容均替换为s所表示的字符串; |
split(s,a[,r]) | 以r为分隔符去切割字符串s,并将切割后的结果保存至a表示的数组中; |
substr(s,i[,n]) | 从s所表示的字符串中取子串,取法:从i表示的位置开始,取n个字符; |
systime() | 取当前系统时间,结果形式为时间戳; |
示例1:返回一个0至1之间的一个随机数
[[email protected] ~]# awk ‘BEGIN {print rand()}‘ 0.237788
示例2:返回/etc/passwd文件中用户名字符串的长度
[[email protected] ~]# awk -F: ‘{print$1,length($1)}‘ /etc/passwd root 4 bin 3 daemon 6 adm 3
示例3:将root用户名中“oo”替换成大写的“OO”
[[email protected] ~]# awk -F:‘/^root/{sub("oo","OO",$0);print $0}‘ /etc/passwd rOOt:x:0:0:root:/root:/bin/bash
示例4:将以root用户名为行的全部“oo”替换成大写的“OO”
[[email protected] ~]# awk -F:‘/^root/{gsub("oo","OO",$0);print $0}‘ /etc/passwd rOOt:x:0:0:rOOt:/rOOt:/bin/bash
示例5:split函数指明字段的分隔符
[[email protected] ~]# awk ‘{split($0,user,":");printuser[1]}‘ /etc/passwd root bin daemon adm
示例6:在/etc/passwd文件中默认shell是/bin/bash的用户,从第7个字段中从4个字符开始取出3个字符
[[email protected] ~]# awk -F:‘/bash$/{char=substr($NF,4,3);printf "%s:%5s\n",$NF,char}‘/etc/passwd /bin/bash: n/b /bin/bash: n/b /bin/bash: n/b /bin/bash: n/b /bin/bash: n/b /bin/bash: n/b /bin/bash: n/b
如果想获取更多的帮助请man awk.