awk工具

awk也是一个很好的数据处理工具。相比于sed常常作用于一整行的处理,awk则比较倾向于将一行分成数个字段来处理。因此,awk相当适合处理小型的数据。awk通常的运行模式是这样的:

[root@localhost opt]#awk ‘条件类型1{动作1}条件类型2{动作2}‘ filename

  awk后面接两个单引号并加上大括号{}来设置想要对数据进行的处理动作。qwk可以处理后续接的文件,也可以读取来自前个命令的standardoutput。但如前面说的,awk主要是处理每一行内的数据,而默认的字段的分隔符为空格键或[tab]键。举例来说,我们用last可以将登陆者的数据读取出来,结果如下所示:

[root@localhost opt]# nl passwd | sed -n '$p'

  37 #This is a test

[root@localhost opt]# last -n 5

root     pts/0        192.168.211.1    Tue Apr 12 09:14   still logged in   

reboot   system boot  2.6.32-431.el6.x Tue Apr 12 09:03 - 16:17 (1+07:13)   

root     pts/0        192.168.211.1    Mon Apr 11 09:57 - crash  (23:05) 

reboot   system boot  2.6.32-431.el6.x Mon Apr 11 09:56 - 16:17 (2+06:20)   

root     pts/0        192.168.211.1    Mon Mar 28 21:47 - crash (13+12:09)  


wtmp begins Sun Jan 24 00:22:20 2016

[root@localhost opt]# last -n 5| awk '{print $1 "\t" $3}'

root 192.168.211.1

reboot boot

root 192.168.211.1

reboot boot

root 192.168.211.1

wtmp Sun

我仅想要取出账号与登陆者信息,且账号与IP之间以[tab]隔开,则会变成如下图:

[root@localhost opt]# last -n 5| grep root |awk '{print $1 "\t" $3}'

root 192.168.211.1

root 192.168.211.1

root 192.168.211.1

 awk最常使用的动作。通过Print的功能将字段数据列出来!字段的分隔则以空格或[tab]按键来隔开。因为不论哪一行都要处理,都要处理,因此,就不需要条件类型的限制!我们想要的是第一列和第三列,但是如上红字体的为什么和别的不一样呢?这是因为数据格式的问题。所以在使用awk的时候,要先确认一下数据,如果是连续的数据,不要有空格或[tab]在内,否则,就会出现那样的情况

 另外,由上面的例子也会知道,在每一行的每个字段都是有变量名称的,那就是$1 $2等变量名称。以上面的例子来说,root就是$1,因为他是第一列!192.168.211.1是第三列,所以就是$3,后面以此类推。还有各变量,就是$0,他代表一整行数据的意思。以上面的例子来说,第一行的$0代表的就是“root”那

一行。由此可知,刚才上面五行当中,整个awk的处理流程是:

1、读入第一行,并将第一行的数据填入$0,$1,$2等变量中;

2、依据条件类型的限制,判断是否需要进行后面的动作;

3、做完所有的动作与条件类型;

4、若还有后续的“行”的数据,则重复上面1-3的步骤,直到所有的数据读完为止。

经过这样的步骤,你会知道,awk是以行为一次处理的单位,而以字段为最小的处理单位。那么awk怎么知道我到底这个数据有几行几列呢?这就需要awk的内置变量的帮忙了,

NF    每一行($0)拥有的字段总数。

NR    目前awk所处理的是“第几行”数据。

FS     目前的分隔字符,默认是空格键。

列出每一列的账号(就是$1)

列出目前处理的行数(就是awk内的NR变量)

并且说明,改行有多少字段(就是awk内的NF变量)


要注意,awk后续的所有动作是以单引号括住的,由于单引号与双引号都必须是成对的,所以,awk的格式内容如查想要以print打印时,记得非变量的文字部分,包含一小节printf提到的格式中,都需要使用双引号来定义出来,因为单引号已经是awk的命令的固定用法。

[root@localhost opt]# last -n 5| grep root |awk '{print $1 "\t lines:" NR "\t colums:" NF}'

root lines:1 colums:10

root lines:2 colums:10

root lines:3 colums:10

awk的逻辑运算符

[root@localhost opt]# cat passwd | awk '{FS=":"} $3<10 {print $1 "\t" $3}'

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

bin 1

daemon 2

adm 3

lp 4

sync 5

shutdown 6

halt 7

mail 8

怎么第一行没有正确的显示出来呢?这是因为我们读入第一行的事后,那些变量$1,$2默认还是以空格键为分隔的,所以虽然我们定义了FS=“:“了,但是却仅能在第二行后才开始生效。那怎么办呢?我们可以预先设置awk变量!利用BEGIN这个关键字,这样做

[root@localhost opt]# cat passwd | awk 'BEGIN {FS=":"} $3<10 {print $1 "\t" $3}'

root 0

bin 1

daemon 2

adm 3

lp 4

sync 5

shutdown 6

halt 7

mail 8

除了BEGIN之外,还有END呢!另外,如果要用awk来进行“计算功能”呢?

[root@localhost opt]# cat pay.txt|awk 'NR==1{printf "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"total"}\

> NR>=2{total = $2+$3+$4\

> printf "%10s %10d %10d %10d %10.2f\n",$1,$2,$3,$4,total}'

所有awk的动作,即在{}内的动作,如果有需要多个命令辅助时,可利用分号;分隔,或者直接以【enter】的按键来隔开每个命令,例如上面

逻辑运算中,如果是“等于”的情况,务必使用两个等号“==”

格式化输出时,在printf的格式设置当中,务必加上\n,才能进行分行

与bash,shell的变量不同,在awk中,变量可以直接使用,不需要加上$符号。