awk与grep,sed号称正则表达式三剑客。他们分别适合不同的需求。
grep适合文本过滤。查找某些关键的行与字符串。
sed适合编辑文本。
AWK:适合文本处理与报表生成。在linux上的AWK为GAWK,当然使用的时候只要执行AWK命令就行,会自动调用GAWK。awk处理文本是这样的,每读进一行,就将其分隔成单独的字段来处理,默认分隔符为空格。如下图,
一,awk的语法结构:
awk [options] 'PATTERN {action}' file1,file2......
1,常用options有两个
(1)-v:声明一个变量
FS为awk内置变量,FS的默认值为空格,且FS表示输入分隔符,下面这条语句表示改变默认分隔符。内置变量在下面会解释
[root@server30 ~]# awk -v FS=: '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
如果不改变默认分符时,得到是下面的结果,将整行都输出来。默认输入输出的分隔符都空格。
[root@server30 ~]# awk '{print $1}' /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
(2)-F:指定输入分隔符,下面表示指定以:为输入分隔符
[root@server30 ~]# awk -F: '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
上面属于print 属于动作(action),使用print,如果有多个字段要显示出来,则需要用逗号将不同字段分隔,以说明是不同两个字段,如果不说明,则输出时会当作一个字段来显示。
用逗号明确告诉awk $1和$3为不同的字段。默认输出的分格符是空格,因此得到两个不同的字段。
[root@server30 ~]# awk -F: '{print $1, $3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
如果不用逗号隔开$1和$3,则会得到下面的结果,将两个字段合并起来。
[root@server30 ~]# awk -F: '{print $1 $3}' /etc/passwd
root0
bin1
daemon2
adm3
lp4
因此从上面结果可以看print的语法: print item1,item2......
还有一个常用printf,而printf比print更好用,printf的语法
printf format item1,item2 .....
format的格式有以下几种:
%c: 显示字符的ASCII码;
%d, %i:十进制整数;
%e, %E:科学计数法显示数值;
%f: 显示浮点数;
%g, %G: 以科学计数法的格式或浮点数的格式显示数值;
%s: 显示字符串;
%u: 无符号整数;
%%: 显示%自身;
对format的修饰符有常用有下面6个:与format结合使用
N:显示宽度,%10s表示每个字段显示10个字符的宽度
-:表示左对齐,默认是右对齐
+:显示数值的符号,如果是正数则显示正号,负数则显示负号
\n表示输出新的一行;
\t表示水平的tab按键;
\v垂直的tab按键;
下面语句中%10s,表示$1显示10个字符的宽度,如果$1小于10字符的宽度,则用空白补充,$5原来是多宽,就多宽,且不自动换行。下面结果在同一行显示
[root@server30 ~]# awk '{printf "%10s,%s",$1,$5}' /etc/issue
Red,Server Kernel,\m , RH033,[root@server30 ~]#
加了\n后,每一行显示完$5后会自动换行,但是结果是右对齐,因为默认是右对齐。结果如下:注意格式之间不能用逗号,不然也会打印出来。
[root@server30 ~]# awk '{printf "%10s,%s\n",$1,$5}' /etc/issue
Red,Server
Kernel,\m
,
RH033,
这样的输出我们自己看来都觉得很乱,因此还需要加-,使结果左对齐,我这在格式之间没有加逗号。
[root@server30 ~]# awk '{printf "%-10s%s\n",$1,$5}' /etc/issue
Red Server
Kernel \m
RH033
2,内置变量:
(1)NF(number of filed):当每行field的个数。(不加$,只用NF表示每一行有多少字段,如果用$NF表示只显示每一行最后一个字段)
NF前不加$的结果:显示每行有多少个字段
[root@server30 ~]# awk '{print NF}' /etc/issue
8
5
0
1
NF前面加$表示,只显示每行的最后
[root@server30 ~]# awk '{print $NF}' /etc/issue
(Tikanga)
\m
RH033
(2)FS(field separator):输入分隔符,默认分隔符是空白字符。前面已经举例。
(3)OFS(out field separator):输出分隔符,默认输出分隔符了是空白字符。
改变输出分隔符如下:
[root@server30 ~]# awk -F: -v OFS=: '{print $1,$7}' /etc/passwd
root:/bin/bash
bin:/sbin/nologin
daemon:/sbin/nologin
adm:/sbin/nologin
lp:/sbin/nologin
如果不定义OFS则默认是空格
[root@server30 ~]# awk -F: '{print $1,$7}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
(4)NR表示 当前处理第几行数据。\t在前面已经解释过
[root@server30 ~]# awk -F: '{print $1 "\tline:" NR}' /etc/passwd
root line:1
bin line:2
daemon line:3
adm line:4
lp line:5
(5)RS: Record separator,默认是换行符;
3,常见的模式类型:
(1)Regexp: 正则表达式,格式为/regular expression/
如果某行包含bash字符串,则就显示出来 /bash/为正则表达式
[root@server30 ~]# awk -F: '/bash/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
student:x:500:500::/home/student:/bin/bash
redhat:x:501:501::/home/redhat:/bin/bash
magedu:x:502:502::/home/magedu:/bin/bash
(2)expresssion: 表达式,其值非0或为非空字符时满足条件,如:$1 ~ /foo/ 或 $1 == "magedu",用运算符~(匹配)和~!(不匹配)。
如果第三个字段大于500,则显示出当前行的第一个字段, $3>500为表达式
[root@server30 ~]# awk -F: '$3>500{print $1}' /etc/passwd
nfsnobody
redhat
magedu
(3)Ranges: 指定的匹配范围,格式为pat1,pat2
awk '/bash/,/nologin/{print $0}' /etc/passwd其中/bash/,/nologin/表示第一次被bash匹配的,与第一次被nologin匹配到的中间所有的行
[root@server30 ~]# awk '/bash/,/nologin/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash (2,3行符合条件)
bin:x:1:1:bin:/bin:/sbin/nologin
student:x:500:500::/home/student:/bin/bash
redhat:x:501:501::/home/redhat:/bin/bash (4-7符合条件)
magedu:x:502:502::/home/magedu:/bin/bash
oprofile:x:16:16:Special user account to be used by OProfile:/home/oprofile:/sbin/nologin
(4)BEGIN/END:特殊模式,仅在awk命令执行前运行一次或结束前运行一次
BEGIN(预处理模式):执行紧跟在BEGIN的代码块
END:执行跟END后面的代码块。
awk -F: '$3>500{printf "%-15s %s\n", $1,$3}' /etc/passwd 在输出结果的第一行之前加一个说明,如果在nftnobody上面加username,65534面加
[root@server30 ~]# awk -F: '$3>500{printf "%-15s %s\n", $1,$3}' /etc/passwd
nfsnobody 65534
redhat 501
magedu 502
awk -F: '$3>500{print "username UID";printf "%-10s %s\n", $1,$3}' /etc/passwd 如果这样做,会造成每一行都会添加username UID
[root@server30 ~]# awk -F: '$3>500{print "username UID";printf "%-10s %s\n", $1,$3}' /etc/passwd
username UID
nfsnobody 65534
username UID
redhat 501
username UID
magedu 502
这样做就达到我们想要的结果awk -F: 'BEGIN{print "username UID"} $3>500 {printf "%-10s %s\n", $1,$3}' /etc/passwd (用{}表示独立的代码块)
[root@server30 ~]# awk -F: 'BEGIN{print "username UID"} $3>500 {printf "%-10s %s\n", $1,$3}' /etc/passwd
username UID
nfsnobody 65534
redhat 501
magedu 502
awk -F: 'BEGIN{print "username UID"} $3>500 {printf "%-10s %s\n", $1,$3} END{print "over"}' /etc/passwd 在最后一行的后面添加一行说明用END。
[root@server30 ~]# awk -F: 'BEGIN{print "username UID"} $3>500 {printf "%-10s %s\n", $1,$3} END{print "over"}' /etc/passwd
username UID
nfsnobody 65534
redhat 501
magedu 502
over
5、Empty(空模式):匹配任意输入行;没有指定模式,所有的行都会被匹配到。
[root@server30 ~]# awk -F: '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
6、常用案例
(1)awk -F: '$1 ~/^root/{print $3,$4,$NF}' /etc/passwd $1表示文本中所有行的第一个字段,^root表示如果第一个字段是root,则显示当这一行的第三个字段,第四个字段,和最后一个字段
(2)awk -F: '$1 !~/^root/{print $3,$4,$NF}' /etc/passwd 表示如果不能被匹配到则显示出来
(3)awk '{if($0 ~/^$/ )print NR }' /etc/issue $0表示文本中全行的所有字符,^$表示空行, 如果某行是空行,NR表示处理第几行数据。打印出空行行号,与下面的效果一样
(4) akw '$0 ~/^$/{print NR }' /etc/issue打印出空行行号
[root@229 ~]# awk '$0 ~/^$/{ print NR} ' /etc/issue
3