20分钟降服awk

2020-05-02 ⏳2.1分钟(0.9千字)

awk是unix下的文本处理工具,功能复杂灵活,可以实现诸如cat, grep, cut, head, sed, wc 等所有文本处理命令的功能。相应的,awk的学习成本也是比较高的。我一直是边用边查边学。网是的内容比较零散,总有一种见树不见林的感觉。今天读到了Awk in 20 Minutes一文,让人拍案教绝。此文从宏观角度分析了awk程序的概念、结构和工作方式,用20%篇幅讲清楚了awk的80%的功能,让人不禁感概想见恨晚。现择其要点分享给大家。


首先,awk脚本的结构是这样的:

# comment
Pattern1 { ACTIONS; }
# comment
Pattern2 { ACTIONS; }

awk从标准输入逐行读取内容,然后使用不同的模式(Pattern)进行匹配,如果匹配成功,则会执行对应大括号内的动作(Action)。这就是awk的执行模型。读取、匹配、执行,就这么简单,所用复杂的功能都是在这个模型之上衍生出来的。


在说模式和动作之间,先简单提一下变量

awk的变量有三种:字符串、数字和字典。字符串和数字可以相互转换。

变量无需声明,可直接使用,如{a=1}。数字变量可以执行数学运算,如{a+=1} 。字典赋值使用方括号,如{a[hi]=1}

awk内置一组特殊变量,分别是$0, $1, ..., $n。它们都以美元符号开头,所面跟一个数字。它们的值取自 awk 读入的文体内容。比如 awk 读入的一行内容为a b c,那么对应的$1的内容为a$2$3的内容分别为bc$0比较特别,其内容是读入的整行即a b c。 awk默认使用一个或多个空白字符切割字段

awk还有另一拨不常用的高级内置变量,在有些场景下有奇效,大家留点印像就好了。

BEGIN { # 用户可以修改
  FS = ",";   # 内容分割符
  RS = "\n";  # 行(记录)分割符
  OFS = " ";  # 输出内容分割符
  ORS = "\n"; # 输出行(记录)分割符
}
{ # 用户无法修改
  NF          # 当前行字段(列)数量
  NR          # 当前行的行数
  ARGV / ARGC # 脚本参数
}

有了变量基础,我们再说模式。模式有三类:正则模式、布尔模式和特殊模式。

典型的正则模式有

/admin/ { ... }     # 匹配包含 admin 的内容
/^admin/ { ... }    # 匹配 admin 开头的内容
/admin$/ { ... }    # 匹配 admin 结尾的内容
/^[0-9.]+ / { ... } # 匹配数字开头的内容
/(POST|PUT|DELETE)/ # 匹配包含部分 http 请求的内容

对于更简单的场景,你还可以直接使用变量比较运算来过滤内容,比如

$1 == 200 { ... } # 匹配状态码为 200 的请求日志(假设第一列为 http 状态码)
$1 >= 500 { ... } # 匹配 5xx 请求
$1 != 200 { ... } # 匹配非 200 请求

你还可以使用布尔表达式将这些匹配模式组合起来,比如

/admin/ || $1 >= 500 # 匹配 admin 接口的 5xx 错误

除此之外,awk还支持两种特殊的模式:BEGINEND,分别在脚本开始之前和结束之后触发。比如awk 'BEGIN{c=0}/admin/{c+=1}END{print c}'会在结束的时候输出含有admin日志的行数


最后说一下动作。简单的动作有

{ a=$1; b=$0 } # 变量赋值
{ c[$1] = $2 } # 字典赋值
{ exit; }      # 结束程序,很少使用
{ next; }      # 跳过当前行

awk还支持条件分支和循环结构,如下

{ if ($3 >= 500) { ACTION }
  else if ($3 >= 400) { ACTION }
  else { ACTION }
}
{ for (i=1; i<x; i++) { ACTION } }
{ for (item in c) { ACTION } }

好了,讲完了。最后给几个示例

统计 user 接口单ip的请求数量超过10次的ip

/user/ { ip=$1; ip_count[ip]++ }
END { for (ip in ip_count) {
  if (ip_count[ip] > 10) { print ip, ip_count[ip] }
} }

请理 ubuntu 的 rc 配置包

dpkg -l|awk '/^rc/ {print $2}'|xargs aptitude purge -y

时间差不多了,你学会了吗?