Lin Hong's TECH Blog! 刀不磨要生锈,人不学习要落后 - Thinking ahead

[原创]AWK 入门示例学习

2016-05-28

最近要处理unix下的文本文件,汇总学习下awk命令。awk处理文本文件中我们常用技巧和示例有哪些?

awk 入门示例学习

最近要处理unix下的文本文件,汇总学习下awk命令。awk处理文本文件中我们常用技巧和示例有哪些?

首先背景概念有:

AWK是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的Family Name的首字符。

Awk的主要特性包含:

  • Awk以记录和字段的方式来查看文本文件

  • 和其他编程语言一样,Awk 包含变量、条件和循环

  • Awk能够进行运算和字符串操作

  • Awk能够生成格式化的报表数据

Awk从一个文件或者标准输入中读取数据,并输出结果到标准输出中。

执行awk程序的方式有多种。你可以输入如下形式的命令行:

awk 'program' input files

打印file1和file2文件中第三个字段为0的每一行的第一个字段。

awk '$3 == 0 { print $1 }' file1 file2

Awk的语法:

awk '/search pattern1/ {Actions}    
     /search pattern2/ {Actions}' file

search pattern是正则表达式

Actions 输出的语法(在Awk 中可以存在多个正则表达式和多个输出定义)

file1/file2 输入文件名

单引号的作用是包裹起来防止shell的截断

Awk的工作方式:

  • 1)Awk 一次读取文件中的一行

  • 2)对于一行,按照给定的正则表达式的顺序进行匹配,如果匹配则执行对应的 Action

  • 3)如果没有匹配上则不执行任何动作

  • 4)在上诉的语法中, Search Pattern 和 Action 是可选的,但是必须提供其中一个

  • 5)如果 Search Pattern 未提供,则对所有的输入行执行 Action 操作

  • 6)如果 Action 未提供,则默认打印出该行的数据

  • 7) {} 这种 Action 不做任何事情,和未提供的 Action 的工作方式不一样

  • 8) Action 中的语句应该使用分号分隔

接下来是示例学习:

示例01.分割/过滤/条件打印

/etc/passwd的文件

[root@chefclient ~]# useradd -u 1061 -g 100 -d /home/james james
[root@chefclient ~]# cat /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
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
systemd-bus-proxy:x:999:997:systemd Bus Proxy:/:/sbin/nologin
systemd-network:x:998:996:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:997:995:User for polkitd:/:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
clientuser:x:1000:1000::/home/clientuser:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
chef:x:1001:1001::/home/chef:/bin/bash
chefnodeadmin:x:1060:100::/home/chefnodeadmin:/bin/bash
james:x:10361:100::/home/james:/bin/bash
[root@chefclient ~]# 

如果想找到uid是1061的用户

[root@chefclient ~]# awk -F':' '$3 == 1061 {print $1,$3}' /etc/passwd
james 1061
[root@chefclient ~]# 

技能点:

-F’:’ 分隔符号是冒号为分割符,默认是空格

{print $1,$3} 是打印第一个和第三个字符,如果是print $0 表示整行。

如果打印匹配james和chef字符的行

[root@chefclient ~]# awk '/james/
> /chef/' /etc/passwd
chef:x:1001:1001::/home/chef:/bin/bash
chefnodeadmin:x:1060:100::/home/chefnodeadmin:/bin/bash
james:x:1061:100::/home/james:/bin/bash
[root@chefclient ~]# 

james用户,chef用户,chefnodeadmin用户都匹配给定的字符串。

如果想找到james的用户

[root@chefclient ~]# awk -F':' '$1 == "james" {print NR,$0}' /etc/passwd
26 james:x:1061:100::/home/james:/bin/bash
[root@chefclient ~]# 

Awk 可以接受任意数量的正则表达式,但是每个组合 ( 正则表达式和对应的 Action) 必须用新行来分隔。

示例02.NF NR

1.打印每一行 { print $0 } 或者 { print }

2.打印特定字段/每行输入中的第一和第三个字段 { print $1, $3 }

3.对字段的值进行计算后再打印出来/计算和打印 { print $1, $2 * $3 }

4.打印行号/Awk会对当前输入的行有多少个字段进行计数, 并且将当前行的字段数量存 储在一个内建的称作 NF 的变量中.

5.Awk的另一个内建变量NR会存储当前已经读取了多少行的计数. 我们可以使用 NR 和 $0 给文件每一行加上行号.

$0 为整行

[root@chefclient ~]# awk -F':' '{print NR"/"NF"   "$0}' /etc/passwd
1/7   root:x:0:0:root:/root:/bin/bash
2/7   bin:x:1:1:bin:/bin:/sbin/nologin
3/7   daemon:x:2:2:daemon:/sbin:/sbin/nologin
4/7   adm:x:3:4:adm:/var/adm:/sbin/nologin
5/7   lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6/7   sync:x:5:0:sync:/sbin:/bin/sync
7/7   shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8/7   halt:x:7:0:halt:/sbin:/sbin/halt
9/7   mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10/7   operator:x:11:0:operator:/root:/sbin/nologin
11/7   games:x:12:100:games:/usr/games:/sbin/nologin
12/7   ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13/7   nobody:x:99:99:Nobody:/:/sbin/nologin
14/7   avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
15/7   systemd-bus-proxy:x:999:997:systemd Bus Proxy:/:/sbin/nologin
16/7   systemd-network:x:998:996:systemd Network Management:/:/sbin/nologin
17/7   dbus:x:81:81:System message bus:/:/sbin/nologin
18/7   polkitd:x:997:995:User for polkitd:/:/sbin/nologin
19/7   tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
20/7   postfix:x:89:89::/var/spool/postfix:/sbin/nologin
21/7   sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
22/7   clientuser:x:1000:1000::/home/clientuser:/bin/bash
23/7   apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
24/7   chef:x:1001:1001::/home/chef:/bin/bash
25/7   chefnodeadmin:x:1060:100::/home/chefnodeadmin:/bin/bash
26/7   james:x:1061:100::/home/james:/bin/bash
[root@chefclient ~]# 

示例03. printf 丰富格式打印

printf 语句的形式如下:

printf(format, value1, value2, ..., valuen)

其中 format 是字符串,包含要逐字打印的文本,穿插着 format 之后的每个值该如何打印的规格(specification)。一个规格是一个 % 符,后面跟着一些字符,用来控制一个 value 的格式。

第一个规格说明如何打印 value1 ,第二个说明如何打印 value2 ,… 。因此,有多少 value 要打印,在 format 中就要有多少个 % 规格。

如:

[root@chefclient ~]# awk -F':' '{printf"No.%d   %s\n",NR,$0}' /etc/passwd
No.1   root:x:0:0:root:/root:/bin/bash
No.2   bin:x:1:1:bin:/bin:/sbin/nologin
No.3   daemon:x:2:2:daemon:/sbin:/sbin/nologin
No.4   adm:x:3:4:adm:/var/adm:/sbin/nologin
No.5   lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
No.6   sync:x:5:0:sync:/sbin:/bin/sync
No.7   shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
No.8   halt:x:7:0:halt:/sbin:/sbin/halt
No.9   mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
No.10   operator:x:11:0:operator:/root:/sbin/nologin
No.11   games:x:12:100:games:/usr/games:/sbin/nologin
No.12   ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
No.13   nobody:x:99:99:Nobody:/:/sbin/nologin
No.14   avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
No.15   systemd-bus-proxy:x:999:997:systemd Bus Proxy:/:/sbin/nologin
No.16   systemd-network:x:998:996:systemd Network Management:/:/sbin/nologin
No.17   dbus:x:81:81:System message bus:/:/sbin/nologin
No.18   polkitd:x:997:995:User for polkitd:/:/sbin/nologin
No.19   tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
No.20   postfix:x:89:89::/var/spool/postfix:/sbin/nologin
No.21   sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
No.22   clientuser:x:1000:1000::/home/clientuser:/bin/bash
No.23   apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
No.24   chef:x:1001:1001::/home/chef:/bin/bash
No.25   chefnodeadmin:x:1060:100::/home/chefnodeadmin:/bin/bash
No.26   james:x:1061:100::/home/james:/bin/bash
[root@chefclient ~]# 

排序sort的添加:

[root@chefclient ~]# awk -F':' '{printf("%d,%s\n"), NR, $0}' /etc/passwd | sort
10,operator:x:11:0:operator:/root:/sbin/nologin
11,games:x:12:100:games:/usr/games:/sbin/nologin
12,ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13,nobody:x:99:99:Nobody:/:/sbin/nologin
14,avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
15,systemd-bus-proxy:x:999:997:systemd Bus Proxy:/:/sbin/nologin
16,systemd-network:x:998:996:systemd Network Management:/:/sbin/nologin
17,dbus:x:81:81:System message bus:/:/sbin/nologin
18,polkitd:x:997:995:User for polkitd:/:/sbin/nologin
19,tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
1,root:x:0:0:root:/root:/bin/bash
20,postfix:x:89:89::/var/spool/postfix:/sbin/nologin
21,sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
22,clientuser:x:1000:1000::/home/clientuser:/bin/bash
23,apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
24,chef:x:1001:1001::/home/chef:/bin/bash
25,chefnodeadmin:x:1060:100::/home/chefnodeadmin:/bin/bash
26,james:x:1061:100::/home/james:/bin/bash
2,bin:x:1:1:bin:/bin:/sbin/nologin
3,daemon:x:2:2:daemon:/sbin:/sbin/nologin
4,adm:x:3:4:adm:/var/adm:/sbin/nologin
5,lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6,sync:x:5:0:sync:/sbin:/bin/sync
7,shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8,halt:x:7:0:halt:/sbin:/sbin/halt
9,mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
[root@chefclient ~]# 

顺序和倒序

[root@chefclient ~]# awk -F':' '{printf("%d,%s\n"), NR, $0}' /etc/passwd | sort -n
1,root:x:0:0:root:/root:/bin/bash
2,bin:x:1:1:bin:/bin:/sbin/nologin
3,daemon:x:2:2:daemon:/sbin:/sbin/nologin
4,adm:x:3:4:adm:/var/adm:/sbin/nologin
5,lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6,sync:x:5:0:sync:/sbin:/bin/sync
7,shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8,halt:x:7:0:halt:/sbin:/sbin/halt
9,mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10,operator:x:11:0:operator:/root:/sbin/nologin
11,games:x:12:100:games:/usr/games:/sbin/nologin
12,ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13,nobody:x:99:99:Nobody:/:/sbin/nologin
14,avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
15,systemd-bus-proxy:x:999:997:systemd Bus Proxy:/:/sbin/nologin
16,systemd-network:x:998:996:systemd Network Management:/:/sbin/nologin
17,dbus:x:81:81:System message bus:/:/sbin/nologin
18,polkitd:x:997:995:User for polkitd:/:/sbin/nologin
19,tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
20,postfix:x:89:89::/var/spool/postfix:/sbin/nologin
21,sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
22,clientuser:x:1000:1000::/home/clientuser:/bin/bash
23,apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
24,chef:x:1001:1001::/home/chef:/bin/bash
25,chefnodeadmin:x:1060:100::/home/chefnodeadmin:/bin/bash
26,james:x:1061:100::/home/james:/bin/bash



[root@chefclient ~]# awk -F':' '{printf("%d,%s\n"), NR, $0}' /etc/passwd | sort -nr
26,james:x:1061:100::/home/james:/bin/bash
25,chefnodeadmin:x:1060:100::/home/chefnodeadmin:/bin/bash
24,chef:x:1001:1001::/home/chef:/bin/bash
23,apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
22,clientuser:x:1000:1000::/home/clientuser:/bin/bash
21,sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
20,postfix:x:89:89::/var/spool/postfix:/sbin/nologin
19,tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
18,polkitd:x:997:995:User for polkitd:/:/sbin/nologin
17,dbus:x:81:81:System message bus:/:/sbin/nologin
16,systemd-network:x:998:996:systemd Network Management:/:/sbin/nologin
15,systemd-bus-proxy:x:999:997:systemd Bus Proxy:/:/sbin/nologin
14,avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
13,nobody:x:99:99:Nobody:/:/sbin/nologin
12,ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
11,games:x:12:100:games:/usr/games:/sbin/nologin
10,operator:x:11:0:operator:/root:/sbin/nologin
9,mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
8,halt:x:7:0:halt:/sbin:/sbin/halt
7,shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
6,sync:x:5:0:sync:/sbin:/bin/sync
5,lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
4,adm:x:3:4:adm:/var/adm:/sbin/nologin
3,daemon:x:2:2:daemon:/sbin:/sbin/nologin
2,bin:x:1:1:bin:/bin:/sbin/nologin
1,root:x:0:0:root:/root:/bin/bash
[root@chefclient ~]# 

示例04. BEGIN与END

特殊模式 BEGIN 用于匹配第一个输入文件的第一行之前的位置, END 则用于匹配处理过的最后一个文件的最后一行之后的位置。

BEGIN { Actions}    
{ACTION} # Action for everyline in a file    
END { Actions }    

在BEGIN 节中的 Actions 会在读取文件中的行之前被执行。

而END 节中的 Actions 会在读取并处理文件中的所有行后被执行。

这个程序使用 BEGIN 来输出一个标题::

BEGIN { print “Name RATE HOURS”; print “”} { print }

只有 Begin

[root@chefclient ~]# awk -F':' 'BEGIN {print "No.\tName\tUserid\tGourid";}{printf("%d\t%s\t%d\t%d\n",NR,$1,$3,$4)}' /etc/passwd
No.	Name	Userid	Gourid
1	root	0	0
2	bin	1	1
3	daemon	2	2
4	adm	3	4
5	lp	4	7
6	sync	5	0
7	shutdown	6	0
8	halt	7	0
9	mail	8	12
10	operator	11	0
11	games	12	100
12	ftp	14	50
13	nobody	99	99
14	avahi-autoipd	170	170
15	systemd-bus-proxy	999	997
16	systemd-network	998	996
17	dbus	81	81
18	polkitd	997	995
19	tss	59	59
20	postfix	89	89
21	sshd	74	74
22	clientuser	1000	1000
23	apache	48	48
24	chef	1001	1001
25	chefnodeadmin	1060	100
26	james	1061	100
[root@chefclient ~]# 

Begin和End

[root@chefclient ~]# awk -F':' 'BEGIN {print "No.\tName\tUserid\tGourid";print"-------------------------------"}{printf("%d\t%s\t%d\t%d\n",NR,$1,$3,$4)} END{print "-------------------------------\nReport End";}' /etc/passwd
No.	Name	Userid	Gourid
-------------------------------
1	root	0	0
2	bin	1	1
3	daemon	2	2
4	adm	3	4
5	lp	4	7
6	sync	5	0
7	shutdown	6	0
8	halt	7	0
9	mail	8	12
10	operator	11	0
11	games	12	100
12	ftp	14	50
13	nobody	99	99
14	avahi-autoipd	170	170
15	systemd-bus-proxy	999	997
16	systemd-network	998	996
17	dbus	81	81
18	polkitd	997	995
19	tss	59	59
20	postfix	89	89
21	sshd	74	74
22	clientuser	1000	1000
23	apache	48	48
24	chef	1001	1001
25	chefnodeadmin	1060	100
26	james	1061	100
-------------------------------
Report End
[root@chefclient ~]# 


[root@chefclient ~]# awk -F':' 'BEGIN {print "No.\tName\tUserid\tGourid";print"-------------------------------";count=0}$4==100{count++}{printf("%d\t%s\t%d\t%d\n",NR,$1,$3,$4)} END{print "-------------------------------\nReport End and GroupId 100 have " count " users";}' /etc/passwd
No.	Name	Userid	Gourid
-------------------------------
1	root	0	0
2	bin	1	1
3	daemon	2	2
4	adm	3	4
5	lp	4	7
6	sync	5	0
7	shutdown	6	0
8	halt	7	0
9	mail	8	12
10	operator	11	0
11	games	12	100
12	ftp	14	50
13	nobody	99	99
14	avahi-autoipd	170	170
15	systemd-bus-proxy	999	997
16	systemd-network	998	996
17	dbus	81	81
18	polkitd	997	995
19	tss	59	59
20	postfix	89	89
21	sshd	74	74
22	clientuser	1000	1000
23	apache	48	48
24	chef	1001	1001
25	chefnodeadmin	1060	100
26	james	1061	100
-------------------------------
Report End and GroupId 100 have 3 users
[root@chefclient ~]# 

简单点的汇总:

[root@chefclient ~]# awk -F':' 'BEGIN {print "No.\tName\tUserid\tGourid";print"-------------------------------";count=0}$4==100{count++;printf("%d\t%s\t%d\t%d\n",NR,$1,$3,$4)} END{print "-------------------------------\nReport End and GroupId 100 have " count " users";}' /etc/passwd
No.	Name	Userid	Gourid
-------------------------------
11	games	12	100
25	chefnodeadmin	1060	100
26	james	1061	100
-------------------------------
Report End and GroupId 100 have 3 users
[root@chefclient ~]# 

注意:$4==100的匹配条件

统计某个文件夹下的文件占用的字节数(注意,统计不包括文件夹的子目录。)

[root@chefclient ~]# ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[total]size is ", size}'
[total]size is  58309416
[root@chefclient ~]# ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[total]size is ", size/1024/1024,"M"}' 
[total]size is  55.6082 M
[root@chefclient ~]# ll
total 56956
-rw-------. 1 root root      951 May 11 04:33 anaconda-ks.cfg
-rwxr-xr-x. 1 root root 58307543 May 12 01:16 chef-12.9.41-1.el7.x86_64.rpm
drwxr-xr-x. 3 root root       89 May 25 04:56 chef-repo
-rwxr-xr-x. 1 root root       72 May 18 23:16 file-create-test01.txt
-rw-r--r--. 1 root root      761 May 29 06:35 netstat.log
[root@chefclient ~]# 

另外内置变量汇总:

ARGC               命令行参数个数
ARGV               命令行参数排列
ENVIRON            支持队列中系统环境变量的使用
FILENAME           awk浏览的文件名
FNR                浏览文件的记录数
FS                 设置输入域分隔符,等价于命令行 -F选项
NF                 浏览记录的域的个数
NR                 已读的记录数
OFS                输出域分隔符
ORS                输出记录分隔符
RS                 控制记录分隔符

示例05.

参考资料

The AWK Programming Language

这个site不错

AWK - Basic Examples



下一篇 Osquery 初体验

Comments