TOC

Linux 文本处理:awk

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 , 默认是空格和 Tab
  • OFS 字段分隔符 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

参考资料与拓展阅读