awk 的文档写出来可能有一本很厚的书,里面甚至有一种内嵌的解释性编程语言在里面。但是我们普通人就把他当一个小工具,了解一下基础用法就好了,不用深入研究。它的基本功能是将字符串切割之后按照 $1
... $n
来处理,$0
表示整个字符串(整行)。
基础示例
# 默认按空格和 Tab 分割
awk '{print $1}' /etc/hosts
# 指定分割,然后使用特殊变量
awk -F: '{print NR ". " $1 "\t" $NF}' /etc/passwd
特殊变量
FILENAME
文件名NF
字段数$NF
用来值最后一个字段NR
行数FNR
当前行数FS
字段分隔符 FieldSep , 默认是空格和 TabOFS
字段分隔符 FieldSep (输出 Output), 默认是空格RS
行分割符 RowSep , 默认是换行符ORS
行分隔符 RowSep (输出 Output), 默认是换行符OFMT
数字输出格式,默认%.6g
函数
https://www.gnu.org/software/gawk/manual/html_node/Built_002din.html
文章中分成六类:数值函数,字符串函数,IO 函数,时间函数,位运算函数,类型函数,多语言函数。
简单使用的话,可能用的多的应该是几个字符串函数:
length([string])
index(in, find)
tolower(string)
toupper(string)
substr(string, start [, length ])
split(string, array [, fieldsep [, seps ] ])
PS:数值性可以直接进行计算,够用了。
综合应用
sum,max,min,avg
# 求和
/bin/top -o %MEM -c -n1 | grep vscode | awk '{print $0;sum+=$11}END{print "总和:",sum}'
# 最大值
/bin/top -o %MEM -c -n1 | grep vscode | awk 'BEGIN{max=0}{print $0;if($11>max)max=$11}END{print "最大值:",max}'
# 最小值
/bin/top -o %MEM -c -n1 | grep vscode | awk 'BEGIN{min=9999}{print $0;if($11<min)min=$11}END{print "最小值:",min}'
# 平均值
/bin/top -o %MEM -c -n1 | grep vscode | awk '{print $0;sum+=$11}END{print "平均值:",sum/NR}'
分组统计
# for
awk '{c[$9]++}END{for(i in c){print i c[i]}}' action.log
# for,printf
awk '{c[$10]++}END{for(i in c){printf "%10d %10d\n",i,c[i]}}' action.log | sort -k2 -r
# if (还可以 else)
awk -F: '{if ($NF != "/sbin/nologin") print $1}' /etc/passwd
# 过滤:跳过第一行
awk -F, 'NR>1{print $1}' students.csv
# 过滤:奇数行
awk -F, 'NR%2==1{print $1}' students.csv
# 过滤:正则表达式
awk -F: '/home/{printf "%20s\t%20s\t%s\n",$1,$(NF-1),$0}' /etc/passwd
PS: end
指最后一行之后,before
指第一行之前
分档统计
tail -n 100000 app.log | grep -F "`date '+[%Y-%m-%d %H:%M:' --date="1 min ago"`" | grep -F 'fileSize' | awk -F'[:,]' 'BEGIN {for(i=0; i<6; i++) { c[i]=0 }} {
if ($5 >= 0 && $5 <= 300000) { c[0]++ }
else if ($5 > 300000 && $5 <= 1000000) { c[1]++ }
else if ($5 > 1000000 && $5 <= 3000000) { c[2]++ }
else if ($5 > 3000000 && $5 <= 10000000) { c[3]++ }
else if ($5 > 10000000 && $5 <= 16000000) { c[4]++ }
else { c[5]++ }} END {for (i in c) {print i,c[i]}}' | sort -nk1
参考资料与拓展阅读
- 阮一峰, awk 入门教程
- awk 中 正则表达式使用