AWK 是一种处理文本文件的编程语言,是一个强大的文本分析工具。之所以叫 AWK 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。
grep 、sed、awk 被称为 linux 中的”三剑客”。grep 更适合单纯的查找或匹配文本, sed 更适合编辑匹配到的文本, awk 更适合格式化文本,对文本进行较复杂格式处理。
1. 使用
1.1 分割字符
1 2 3
| echo 'this is a test' | awk '{print $0}'
this is a test
|
print 是打印命令,$0 代表当前行全部字段。上面代码中,print $0
就是把标准输入 this is a test
,重新打印了一遍。
awk 会根据空格和制表符,将每一行分成若干字段,依次用 $1、$2、$3 代表第一个字段、第二个字段、第三个字段等等。
1 2 3
| echo 'this is a test' | awk '{print $3}'
a
|
下面,为了便于举例,我们把/etc/passwd 文件保存成 demo.txt。
1 2 3 4 5
| root:x:0:0:root:/root:/usr/bin/zsh daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync
|
这个文件的字段分隔符是冒号(:),所以要用 -F 参数指定分隔符为冒号。然后,才能提取到它的第一个字段。
1 2 3 4 5 6 7 8 9 10
| awk -F ':' '{ print $1 }' demo.txt awk -v FS=':' '{print $1}' demo.txt cat demo.txt | awk -F ':' '{print $1}'
root daemon bin sys sync
|
1.2 变量使用
1.2.1 NF 字段
变量 NF 表示当前行有多少个字段,因此 $NF 就代表最后一个字段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
echo 'this is a test' | awk '{print $NF}' test
echo 'this is a test' | awk '{print $(NF-1)}' a
awk -F ':' '{print $1, $(NF-1)}' demo.txt root /root daemon /usr/sbin bin /bin sys /dev sync /bin
|
1.2.2 NR 行
变量 NR 表示当前处理的是第几行。
1 2 3 4 5 6 7 8 9
| awk -F ':' '{print NR ") " $1}' demo.txt
1) root 2) daemon 3) bin 4) sys 5) sync
|
1.2.3 常用内置变量
1 2 3 4 5 6
| FILENAME:当前文件名 FS:字段分隔符,默认是空格和制表符。 RS:行分隔符,用于分割每一行,默认是换行符。 OFS:输出字段的分隔符,用于打印时分隔字段,默认为空格。 ORS:输出记录的分隔符,用于打印时分隔记录,默认为换行符。 OFMT:数字输出的格式,默认为%.6g。
|
1.3 函数使用
1.3.1 Toupper
1 2 3 4 5 6 7 8
| awk -F ':' '{ print toupper($1) }' demo.txt
ROOT DAEMON BIN SYS SYNC
|
1.3.2 常用内置函数
1 2 3 4 5 6 7 8
| tolower():字符转为小写。 length():返回字符串长度。 substr():返回子字符串。 sin():正弦。 cos():余弦。 sqrt():平方根。 rand():随机数。
|
1.4 条件使用
awk
允许指定输出条件,只输出符合条件的行。输出条件要写在动作的前面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| awk -F ':' '/usr/ {print $1}' demo.txt
root daemon bin sys
awk -F ':' 'NR % 2 == 1 {print $1}' demo.txt
root bin sync
awk -F ':' 'NR >3 {print $1}' demo.txt
sys sync
awk -F ':' '$1 == "root" || $1 == "bin" {print $0}' demo.txt
root:x:0:0:root:/root:/bin/bash bin:x:2:2:bin:/bin:/usr/sbin/nologin
|
1.5 If 语句
awk 提供了 if 结构,用于编写复杂的条件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| awk -F ':' '{if ($1 > "m") print $1}' demo.txt
root sys sync
awk -F ':' '{if ($1 > "m") print $1; else print "---"}' demo.txt
root --- --- sys sync
|
1.6 循环使用
END 的意思是“处理完所有的行的标识”,除了 END 还有 BEGIN,这两个关键字意味着执行前和执行后的意思,语法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| ls -l *.log -rw-rw-r-- 1 web web 42487 Nov 12 2021 openfiles1111.log -rw-rw-r-- 1 web web 2690 Nov 12 2021 openfiles1112.log
ls -l *.log | awk '{sum+=$5} END {print sum}' 45177
ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.3 0.0 171948 11688 ? Ss 2022 1087:09 /lib/systemd/systemd --system --deserialize 29 root 2 0.0 0.0 0 0 ? S 2022 0:36 [kthreadd] root 3 0.0 0.0 0 0 ? I< 2022 0:00 [rcu_gp] root 4 0.0 0.0 0 0 ? I< 2022 0:00 [rcu_par_gp]
ps aux | awk 'NR!=1{a[$1]+=$6;} END { for(i in a) print i ", " a[i]"KB";}'
systemd+, 179468KB ubuntu, 176548KB web, 1073020KB message+, 6484KB syslog, 4728KB mongodb, 407824KB redis, 19880KB consul, 47884KB grafana, 71188KB nobody, 4116KB www-data, 69308KB uuidd, 1032KB mysql, 1420364KB daemon, 2180KB root, 4716836KB
|
2. Awk 脚本
2.1 执行逻辑
1
| awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
|
BEGIN 语句块在 awk 开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在 BEGIN 语句块中。
END 语句块 在 awk 从输入流中读取完所有的行 之后 即被执行,比如打印所有行的分析结果这类信息汇总都是在 END 语句块中完成,它也是一个可选语句块。
pattern 语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供 pattern 语句块,则默认执行{ print },即打印每一个读取到的行,awk 读取的每一行都会执行该语句块。
1 2 3 4 5 6 7
| echo -e "A line 1\nA line 2" | awk 'BEGIN{ print "Start" } { print } END { print "End" }'
Start A line 1 A line 2 End
|
2.2 将外部变量值传递给 awk
借助 -v 选项,可以将外部值(并非来自 stdin)传递给 awk:
1 2 3 4
| VAR=10000 echo | awk -v VARIABLE=$VAR '{ print VARIABLE }'
10000
|
另一种传递外部变量方法:变量之间用空格分隔作为 awk 的命令行参数跟随在 BEGIN、{}和 END 语句块之后。
1 2 3 4 5
| var1="aaa" var2="bbb" echo | awk '{ print v1,v2 }' v1=$var1 v2=$var2
aaa bbb
|
2.3 测试
1 2 3 4 5 6 7
| netstat -anp | grep 3306 | awk '$NF != "-" {print $NF}' | awk -F '/' '{print $1}'
awk 'length>80' demo.txt
|
3. 参考资料