二十八、awk

awk:流式编辑器,针对文档的行进行操作。awk兼具sed的所有功能,且更强大。可以对每段做匹配,不能更改文件内容,不像sed有-i选项能更改内容。

截取文档中的某段,示例:

-F:指定分隔符,若不加-F,则以空格或tab为分隔符。print为打印的动作,用来打印某个字段。$1为第一个字段,以此类推,$0表示整行

# awk -F ':' {print $1} test.txt                      打印第一段

# head -n2 test.txt |awk -F ':' '{print $1}'     打印前两行的第一段

# head -n2 test.txt |awk -F ':' '{print $0}'     打印前两行整行(所有段)

# awk -F ':' '{print $1,$2,$4}' test.txt           多打印几段,用逗号隔开;也可用#,但是#麻烦一点,要用双引号括起来,示例:

# awk -F ':' '{print $1"#"$2"#"$4}' test.txt

root#x#0

bin#x#1

daemon#x#2

# awk -F ':' '{print $0}' test.txt                      打印所有行

不指定分隔符,示例:

# awk '{print $1}' 1.txt

1

aa

cc

# cat 1.txt

1  2

aa  bb

cc  d

匹配字符或字符串

# awk '/ot/' test.txt                      指定字符为ot

root:x:0:0:root:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologi

# awk  -F ':' '$1 ~/oo/' test.txt    

root:x:0:0:root:/root:/bin/bash

精确匹配,第一段里包含oo的行,1后加个~。~为匹配的意思。这就是比grep和sed更强大的地方,对段匹配。同样也支持正则,如o+,o*等等。所有符号都不用加脱义字符,这是awk比grep和sed方便的地方。

# awk  -F ':' '/root/ {print $1,$2} /user/ {print $1,$2}' test.txt  多次匹配

先匹配root,再匹配user。

条件操作符

逻辑符号判断,==为等于,还有>、>=、<、<=、!=等,!=为不匹配。若把比较的数字用双引号括起来,awk会认为是字符,不括起来会认为是数字。

# awk -F ':' '$3=="0"' test.txt

# awk -F ':' '$3>="0"' test.txt

# awk -F ':' '$3>=500' test.txt

匹配数字时不要加双引号,否则认为是字符

# awk -F ':' '$7!="/sbin/nologin"' test.txt   是字符串,所以要加上双引号

# awk -F ':' '$3<$4' test.txt  两个段之间进行逻辑比较,第三段小于第四段

||和&&,分别表示“或者”,“并且”。示例:

# awk -F ':' '$3<"4" && $3<"7"' test.txt

此处4和7代表字符,所以要用双引号括起来。

# awk -F ':' '$3>1000 || $7=="/bin/bash"' test.txt

第三段大于1000,或者第七段等于/bin/bash的。

# awk -F ':' '$3>1000 || $7 ~ /bash/' test.txt

匹配第七段为bash的,或者第三段大于1000的。

awk的内置变量

awk常用变量:OFS、NF和NR。

OFS:和-F选项有类似的功能,也是用来定义分隔符的,但是它是在输出的时候定义。

NF:表示用分隔符分隔后一共有多少段

NR:表示行号

OFS用法示例:

# head -n5 test.txt |awk -F ':' '{OFS="#"} {print $1,$3}'  

定义分隔符为#,也可以定义为@

root#0

bin#1

daemon#2

adm#3

lp#4

更高级的用法,示例:

# awk -F ':' '{OFS="#"} {if ($3<1000) {print $1,$3,$4}}' /etc/passwd

if:如果,判断的作用。如果$3<1000 则打印出 $1$3$4 ,输出并以#分隔显示。

NF用法示例:

# awk -F ':' '{print NF":" $0}' test.txt  显示所有段有多少段。

# awk -F ':' 'NF==7 && $1 ~ /root|sync/' test.txt   配合匹配一起用

# head -n3 /etc/passwd |awk -F ':' '{print NF}'

7

7

7

# head -n3 /etc/passwd |awk -F ':' '{print $NF}'

/bin/bash

/sbin/nologin

/sbin/nologin

此处NF是多少段,$NF是最后一段的值。

NF:表示用分隔符分隔后一共有多少段

NR用法示例:

# awk -F ':' '{print NR":" $0}' test.txt  显示所有段的行号

# head -n3 /etc/passwd |awk -F ':' '{print NR}'

1

2

3

# awk -F ':' 'NR<=10' test.txt  前十行,NR可作为判断条件。

NR也可配合段匹配一起使用,示例:

# awk -F ':' 'NR<=10 && $1 ~ /root|sync/' test.txt

NR:表示行号

# awk -F ':' '{print $NR":"$NF}' test.txt 显示出的内容将从$1开始往后推。

awk中的数学运算

awk可以更改段值,示例:

# head -n3 test.txt  | awk -F ':' '$1="root"'  

root x 0 0 root /root /bin/bash

root x 1 1 bin /bin /sbin/nologin

root x 2 2 daemon /sbin /sbin/nologin

# head -n3 test.txt  | awk -F ':' '{OFS=":"} $1="root"'

root:x:0:0:root:/root:/bin/bash

root:x:1:1:bin:/bin:/sbin/nologin

root:x:2:2:daemon:/sbin:/sbin/nologin

此处是一个等于号,是赋值的意思,两个等于号就是匹配出来的意思,要分清楚。可以看到前三行的第一段都变为了root。可以直接定义分隔符为“:”。

计算某个段的总和,示例:

# awk -F ':' '{(tot=tot+$3)}; END {print tot}' test.txt

4610

(表示每一行的第三段相加,最后再print求和)

END:awk特有语法,表示所有的行都执行。

if:判断。

for:循环。

# awk -F ':' '{if ($1=="root") {print $0}}' test.txt

root:x:0:0:root:/root:/bin/bash

先判断第一段有root的,再打印整行。