awk在CentOS操作系统中是一个软链接,链接到gawk程序上的。awk主要是对文件的行进行操作,将一行按照指定的方式进行切割。

 

一、awk工作机制

  awk在处理文本流时,每一次会读取文本流中的一行并对这一行按指定的分隔符进行分隔,分隔后可以对每一个字段进行处理,其中输入的分隔符可以和输出的分隔符不一样,这些都是通过awk内置的变量来处理的。

 

二、awk命令运用

格式:awk [OPTIONS] 'program' FILE1 FILE2 ...

2.1 print

用法:print item1,item2,….

示例1:输出/etc/passwd文件中的第1个字段和第3个字段的值

[root@node-3 ~]# awk -F: '{print $1,$3}'/etc/passwdroot 0bin 1daemon 2adm 3

根据输出结果进行分析:

(1)-F:用于指明输入字段的分隔符

(2)每个item之间用逗号分隔,输出时的分隔符为空白字符;

(3)如果print在输出时省略了item,将会输出整行的内容

 

示例2:根据上示例的要求,进行以“Name:root,UID:0”的格式输出

[root@node-3 ~]# awk -F: '{print"Name:"$1,",UID:"$3}' /etc/passwdName:root ,UID:0Name:bin ,UID:1Name:daemon ,UID:2

根据输出结果进行分析:

(1)在各item中以“”引号的内容将会原样的输出

(2)数值会被隐式转换为字符串进行输出

 

2.2 awk变量

  awk的变量有内建变量和自定义的变量,内建变量是awk事先就已经定义好了,直接使用变量名就可以了,自定义变量根据情况的需求进行定义。

2.2.1 自定义变量

格式:-v VAR_NAME=VALUE

示例:[root@node-3 ~]# awk -v file="abc""{print file}" /etc/passwdabcabcabc

根据输出结果进行分析:

(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个字段,原文件如下:

[root@node-3 ~]# cat /etc/passwdroot:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologin

 

[root@node-3 ~]# awk -v FS="[:/]"'{print $1,$7}' /etc/passwdroot rootbin bindaemon sbin

根据输出结果进行分析:

(1)-v:对变量进行赋值,包含内建变量和自定义变量;

(2)FS是awk的内建变量,表示指定字符之间的分隔符;

(3)FS的值要用双引号引起来,如果要指定多个分隔直接写在“[]”中即可。

 

示例2:测试文件如下,以“,”为行结束符,输出整行的内容,接着输出第1字段、第3字段:

[root@node-3 ~]# cat awk.txt how are you , how old are  you ?how old your , Yes are you ? [root@node-3 ~]# awk -v RS=","'{print $0}' awk.txt how are you  howold are  you ?how old your  Yesare you ?[root@node-3 ~]# awk  -v FS=" " -v RS=","  '{print $1,$3}' awk.txt how youhow areYes you

根据输出结果进行分析:

(1)RS改变了行结束符,默认的行结束符可以使用cat -A awk.txt查看。

(2)-v选项可以使用多次,每定义一个变量的值,要使用一次“-v”选项。

 

示例3:根据/etc/passwd文件中输出第1字段和第3字段,格式为“root:0”,原文件如下:

[root@node-3 ~]# cat /etc/passwdroot:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologin

 

方法1:[root@node-3 ~]# awk -F:  -v OFS=":" '{print $1,$3}'/etc/passwdroot:0bin:1daemon:2方法2:[root@node-3 ~]# awk -F:  '{print $1":"$3}' /etc/passwdroot:0bin:1daemon:2

根据输出结果进行分析:

(1)-v OFS=”:”用于定义输出字段之间的分隔符,默认为空白字符

(2)方法2中的 pirnt $1”:”$3,中的双引号中的内容会原样的输出,这就是字符串之间的连接

 

示例4:将示例3中的输出结果以“,”会换行符。

[root@node-3 ~]# awk -F: -vORS="," '{print $1":"$3}' /etc/passwdroot:0,bin:1,daemon:2,[root@node-3 ~]#

根据输出结果进行分析:

(1)ORS更改默认的换行符将以指定符号输出

 

示例5:根据如下文件内容,输出字段的个数,并显示最后一个字段的内容

[root@node-3 ~]# cat awk.txt how are you , how old are  you ?how old your , Yes are you ? [root@node-3 ~]# awk '{print NF,$NF}'awk.txt 9 ?8 ?

根据输出结果进行分析:

(1)NF使用显示被分隔符分隔后的字段个数。

(2)$后面跟上一个数字用于显示指定字段的内容,而NF是一个数字,替换后就是显示最后一个字段。

 

示例6:显示awk.txt和/etc/passwd文件行号

[root@node-3 ~]# awk '{print NR,$0}'awk.txt /etc/passwd1 how are you , how old are  you ?2 how old your , Yes are you ?3 root:x:0:0:root:/root:/bin/bash4 bin:x:1:1:bin:/bin:/sbin/nologin5 daemon:x:2:2:daemon:/sbin:/sbin/nologin [root@node-3 ~]# awk '{print FNR,$0}'awk.txt /etc/passwd1 how are you , how old are  you ?2 how old your , Yes are you ?1 root:x:0:0:root:/root:/bin/bash2 bin:x:1:1:bin:/bin:/sbin/nologin3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

根据输出结果进行分析:

(1)awk后可以跟多个文件

(2)NR变量在对多个文件显示行号时,后一个文件的行号是接着前一个文件的行号继续增加显示的

(3)FNR变量对多个文件是分别进行显示行号

 

示例7:显示awk当前正在处理的文件名

[root@node-3 ~]# awk '{print FNR,FILENAME}'awk.txt /etc/passwd1 awk.txt2 awk.txt1 /etc/passwd2 /etc/passwd3 /etc/passwd

 

示例8:根据示例7显示awk的参数个数及第2个参数的值

[root@node-3 ~]# awk '{printFNR,FILENAME,ARGC,ARGV[1]}' awk.txt /etc/passwd 1 awk.txt 3 awk.txt2 awk.txt 3 awk.txt1 /etc/passwd 3 awk.txt2 /etc/passwd 3 awk.txt3 /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文件进行格式化输出

[root@node-3 ~]# 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[root@node-3 ~]# 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的用户

[root@node-3 ~]# awk -F: '$3>500{print$1,$3}' /etc/passwdnfsnobody 65534testuser 1000centos 1001user1 1002gentoo 1003

 

示例2:显示/etc/passwd文件中每行字段中包含有bash字符的行

[root@node-3 ~]# awk -F:'$0~"bash"{print $0}' /etc/passwdroot:x:0:0:root:/root:/bin/bashbbs:x:496:493::/home/bbs:/bin/bashtestuser:x:1000:500::/home/testuser:/bin/bashcentos:x:1001:1001::/home/centos:/bin/bashuser1:x:1002:1002:chrootuser:/home/user1:/bin/bashgentoo:x:1003:1003::/home/gentoo:/bin/bashnginx:x:495:492::/home/nginx:/bin/bash

 

示例3:判断用户UID是否大于等于500,格式化显示用户名信息

[root@node-3 ~]# 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结尾的行

[root@node-3 ~]# awk -F: '/bash$/{print$0}' /etc/passwdroot:x:0:0:root:/root:/bin/bashbbs:x:496:493::/home/bbs:/bin/bashtestuser:x:1000:500::/home/testuser:/bin/bashcentos:x:1001:1001::/home/centos:/bin/bashuser1:x:1002:1002:chrootuser:/home/user1:/bin/bashgentoo:x:1003:1003::/home/gentoo:/bin/bashnginx:x:495:492::/home/nginx:/bin/bash

 

示例2:在/etc/passwd文件中显示UID大于500的用户名

[root@node-3 ~]# awk -F: '$3>500{print$1}' /etc/passwdnfsnobodytestusercentosuser1gentoo

 

示例3:统计/etc/passwd文件中所有UID的和

[root@node-3 ~]# awk 'BEGIN{FS=":";sum=0}{sum+=$3}END{print sum}' /etc/passwd73318

根据输出结果进行分析:

(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

[root@node-3 ~]# 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的用户名

[root@node-3 ~]# awk -F:'{if($3>500){print $1,$3}}' /etc/passwdnfsnobody 65534testuser 1000centos 1001user1 1002gentoo 1003

 

示例2:判断/etc/inittab的字段数大于6的,以空格分隔的

[root@node-3 ~]# 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.conf7 # Individual runlevels are started by/etc/init/rc.conf9 # Terminal gettys are handled by/etc/init/tty.conf and /etc/init/serial.conf,12 # For information on how to writeupstart event handlers, or how8 # 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的字符

[root@node-3 ~]# awk '{i=1;while(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文件中以空格为分隔符,显示每个字段的长度

[root@node-3 ~]# 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的就不在判断后面的字段的字符数

[root@node-3 ~]# awk -F:'{for(i=1;i<=NF;i++){if(length($i)>10){break}else {printlength($i),$i}}}' /etc/passwd4 root1 x1 01 04 root5 /root9 /bin/bash3 bin1 x1 11 1

 

2.6.5 next

next用于提前结束对本行文本的处理,而提前进入下一行的处理操作;

 

示例:显示/etc/passwd中UID是奇数的用户名和UID

[root@node-3 ~]# awk -F: '{if($3%2==0)next;print $1,$3}' /etc/passwdbin 1adm 3sync 5halt 7operator 11gopher 13nobody 99

 

2.7 数组

格式:array[index-expression]

  其中index-expression可以是任意字符,如果某数组元素事先不存在,则在引用时,awk会自动创建元素并将其值初始化为空串,awk的数组下标是从1开始编号的。

如果要遍历数组中的元素,则要使用for (var_name in array)

 

示例:统计当前系统上所有tcp连接的各种状态的个数;

[root@node-3 ~]# netstat  -tan|awk '/^tcp/{count[$NF]++}END{for(i incount){print i,count[i]}}'TIME_WAIT 4000ESTABLISHED 2LISTEN 8

 

示例:统计指定的web访问日志中各ip的资源访问次数:

[root@node-3 ~]# awk '{ip[$1]++}END{for (iin ip){print i,ip[i]}}' /var/log/httpd/access_log172.16.9.35 4016172.16.9.7 186172.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之间的一个随机数

[root@node-3 ~]# awk 'BEGIN {print rand()}'0.237788

 

示例2:返回/etc/passwd文件中用户名字符串的长度

[root@node-3 ~]# awk -F: '{print$1,length($1)}' /etc/passwdroot 4bin 3daemon 6adm 3

 

示例3:将root用户名中“oo”替换成大写的“OO”

[root@node-3 ~]# awk -F:'/^root/{sub("oo","OO",$0);print $0}' /etc/passwdrOOt:x:0:0:root:/root:/bin/bash

 

示例4:将以root用户名为行的全部“oo”替换成大写的“OO”

[root@node-3 ~]# awk -F:'/^root/{gsub("oo","OO",$0);print $0}' /etc/passwdrOOt:x:0:0:rOOt:/rOOt:/bin/bash

 

示例5:split函数指明字段的分隔符

[root@node-3 ~]# awk '{split($0,user,":");printuser[1]}' /etc/passwdrootbindaemonadm

示例6:在/etc/passwd文件中默认shell是/bin/bash的用户,从第7个字段中从4个字符开始取出3个字符

[root@node-3 ~]# 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.