awk
相较于 sed 常常作用于一整个行的处理,awk 则比较倾向于一行当中分成数个“字段”来处理。因此(格式化输出),awk相当的适合处理小型的数据数据处理呢!awk通常运行的模式是这样的:
awk 后面接两个单引号并加上大括号 {} 来设置想要对数据进行的处理动作。awk 可以处理后续接的文件,也可以读取来自前个指令的 standardoutput 。但如前面说的,awk 主要是处理“每一行的字段内的数据”,而默认的“字段的分隔符号为"空白键"或 "[tab]键" ”!
举例来说,我们用 last 可以将登陆者的数据取出来,显示前5行
[root@base ~]# last -n 5
root pts/2 192.168.1.1 Wed Mar 25 14:48
still logged in
root pts/0 192.168.1.1 Tue Mar 24 17:19
still logged in
root pts/1 192.168.1.1 Tue Mar 24 17:15
still logged in
root pts/0 192.168.1.1 Tue Mar 24 16:55 -17:19 (00:23)
reboot system boot 5.4.6-1.el7.elre Tue Mar 24 16:55 - 15:59 (23:04)
wtmp begins Sat Dec 28 00:27:26 2019
若我想要取出帐号与登陆者的 IP ,且帐号与 IP 之间以 [tab] 隔开,则会变成这样:
[root@base ~]# last -n 5 | awk '{print $1 "\t" $3}'
root 192.168.1.1
root 192.168.1.1
root 192.168.1.1
root 192.168.1.1
reboot boot
wtmp Sat
整个 awk 的处理流程是:1. 读入第一行,并将第一行的数据填入 $0, $1, $2.... 等变量当中;
2. 依据 "条件类型" 的限制,判断是否需要进行后面的 "动作";
3. 做完所有的动作与条件类型;
4. 若还有后续的“行”的数据,则重复上面 1~3 的步骤,直到所有的数据都读完为止。
经过这样的步骤,你会晓得, awk 是“以行为一次处理的单位”,而“以字段为最小的处理单位”。好了,那么 awk 怎么知道我到底这个数据有几行?有几栏呢?这就需要 awk 的内置变量的帮忙啦~
我们继续以上面 last -n 5 的例子来做说明,如果我想要:
列出每一行的帐号(就是 $1);
列出目前处理的行数(就是 awk 内的 NR 变量)
并且说明,该行有多少字段(就是 awk 内的 NF 变量)
awk 后续的所有动作是以单引号括住的,由于单引号与双引号都必须是成对的, 所以, awk 的格式内容如果想要以print 打印
[root@base ~]# last -n 5| awk '{print $1 "\t lines: "NR"
\t columns: " NF}'
root lines: 1 columns: 10
root lines: 2 columns: 10
root lines: 3 columns: 10
root lines: 4 columns: 10
reboot lines: 5 columns: 11
lines: 6 columns: 0
wtmp lines: 7 columns: 7
awk的逻辑运算字符
举例来说,在 /etc/passwd 当中是以冒号 ":" 来作为字段的分隔,该文件中第一字段为帐号,第三字段则是 UID。那假设我要查阅,第三栏小于 10 以下的数据,并且仅列出帐号与第三栏,那么可以这样做:
[root@base ~]# cat /etc/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 这个关键字喔!这样做:
~]# cat /etc/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