Linux 三剑客之 awk 文本分析利器

三剑客收官篇。grep 管找、sed 管改,最硬核的算账活儿归 awk。它按列切分文本,取字段、做运算、搞统计样样行,与其说是命令,更像一门小语言。这篇从三剑客分工讲起,把 awk 的字段、条件、变量和 BEGIN/END 脚本重新捋一遍。

三剑客系列写到这,grep 和 sed 都聊过了,就剩最后一位——awk。

其实很多年前我单独写过一篇 awk 的文章(/post/100.html),当时只是零散记了些用法。这回借着三剑客系列,把它跟 grep、sed 摆一块儿,重新捋一遍,讲得更成体系一点。

awk 是三剑客里最“重”的一个。前两位还算命令,awk 基本可以算半门语言了。

先照例把三剑客分工过一遍,再重点啃 awk。

三剑客各自干啥

老规矩,三个命令各管一摊。

  • grep:负责找。从文本里把符合条件的行捞出来,只筛选不改内容。
  • sed:负责改。流式编辑器,按行做替换、删除、插入。
  • awk:负责算。把每行按列切开,取字段、做统计、搞运算,处理结构化文本最强。

一份日志摆面前的三种诉求:

  • 挑出所有报错的行 → grep
  • 把旧域名批量换成新域名 → sed
  • 统计每个接口被调用了多少次 → awk

今天主角是 awk,那位管“算”的。

awk 为什么像门语言

awk 这名字来头挺有故事,是三位创始人 Alfred Aho、Peter Weinberger、Brian Kernighan 姓氏首字母拼出来的。

三个人凑一块儿搞出来的东西,果然不简单。

它有一堆参数、支持各种脚本写法、能引入脚本文件、还有变量和条件判断。与其说它是个命令,不如说是一套文本处理的语言规范。

正因为它大而全,我这篇不打算把每个参数都摊开讲。真那么搞,反而越学越乱。

我们抓住它最核心的那条主线:按列切分,再挑字段处理。这条吃透了,日常八成场景都够用。

按列切分是 awk 的立身之本

awk 干的第一件事,就是把每一行按分隔符切成一段一段,然后用 $1、$2、$3 这样去取第几列。

$0 比较特殊,代表整行。

默认它按空格或 TAB 切分:

# 把 mebugs.log 每行切开,输出第一列和第二列
awk '{print $1,$2}' mebugs.log
​

那个 {print ...} 是 awk 的动作,包在花括号里,意思是“对每一行都干这件事”。

它也能接管道,处理前面命令的输出,这个用法其实更常见:

# 从管道来的文本按逗号切,取第一列
grep "123,122" mebugs.log | awk -F, '{print $1}'
​

这里的 -F 是指定分隔符,-F, 就是按逗号切。它对应 awk 的内置变量 FS(field separator,字段分隔符)。

不指定就是默认的空格和 TAB。

# 明确按逗号切,取第一列和第二列
awk -F, '{print $1,$2}' mebugs.log
​

-F 还能塞正则、塞多个字符当分隔条件,遇到特殊符号用单引号 '...' 包起来就行。

实际干活我基本都是「管道 + awk 取列」这个组合,比直接怼文件灵活太多。

条件筛选顺手就做了

awk 取列的同时,还能顺手按条件挑行,省得再套一层 grep。

用运算符过滤

直接拿列的值去比大小、比相等:

# 第一列大于 15 的行,整行输出
awk '$1>15' mebugs.log

# 第一列等于 15 的行,只输出第一列和第三列
awk '$1==15 {print $1,$3}' mebugs.log

# 第一列大于 15 且第二列等于 mebugs 的行,输出前三列
awk '$1>15 && $2=="mebugs" {print $1,$2,$3}' mebugs.log
​

&& 是“并且”,多个条件串一块儿。前面写条件、后面花括号写动作,条件成立才执行动作。

没写动作时,默认动作就是把整行打出来(相当于 {print $0})。

用正则筛

awk 里也能用正则,把模式用 /.../ 包起来:

# 包含 mebugs 的行,整行输出(这活儿 grep 也能干)
awk '/mebugs/' mebugs.log

# 第五列匹配 mebugs 的行,只输出第二列和第四列
awk '$5 ~ /mebugs/ {print $2,$4}' mebugs.log
​

那个 ~ 是“匹配”的意思,$5 ~ /mebugs/ 就是“第五列里含 mebugs”。

这种「指定某一列去匹配」的能力,grep 就干不了,grep 只能整行匹配。这也是 awk 比 grep 更“精细”的地方。

变量让输出更随心

awk 支持自定义变量,用 -v 传进去,能在输出时顺手做点加工。

# 传入 a=1、b=com
# 输出:第一列、第一列加 a、第一列拼接 b
# 假设某行是  12 mebugs.
# 结果就是   12 13 12com
awk -v a=1 -v b=com '{print $1,$1+a,$1 b}' mebugs.log
​

$1+a 是把第一列当数字做加法,$1 b 是把第一列和变量 b 拼在一起(awk 里两个东西挨着写就是字符串拼接)。

有了变量,很多本来要再写个循环去加工的活儿,一条命令里就顺手做完了。

上升到脚本 BEGIN 和 END

前面都是处理“每一行”。awk 还给了两个特殊时机,让你在所有行之前和之后各插一脚。

BEGIN { 处理任何行之前,先执行这里 }
      { 每读到一行,执行这里 }
END   { 所有行处理完,最后执行这里 }
​

这三段配合起来,awk 就有了完整的“开场—逐行—收尾”结构,statistic 统计这类活儿全靠它。

举个最典型的,统计一个文件总共多少行、某列的总和:

# BEGIN 先打个表头,中间对每行累加第一列,END 收尾输出合计
awk 'BEGIN{print "开始统计"} {sum += $1} END{print "合计:", sum}' nums.txt
​
  • BEGIN 里打了个开头
  • 中间每行把第一列累加到 sum
  • END 里把最终的 sum 打出来

这就是 awk 当“计算器”用的经典套路,count、sum、去重统计都是这个骨架。

脚本太长写在命令行里难受,可以单独存成文件,用 -f 引入:

# 把 awk 脚本写进文件,再用 -f 加载
awk -f stat.awk mebugs.log
​

更复杂的脚本写法我就不深入了,因为我也不怎么用。真到那份上,可能直接上 Python 更省心。

大写滑稽,小写尴尬,哈哈哈~~

小结

三剑客到这就凑齐了:grep 找、sed 改、awk 算。

awk 这位收官选手,抓住几条主线就不虚:

  • 核心是按列切分,$1 $2 ... 取列,$0 是整行,-F 指定分隔符
  • 取列的同时能用运算符和正则顺手筛行,还能指定某一列去匹配
  • -v 传变量,输出时做加减和拼接
  • BEGIN / END 撑起“开场—逐行—收尾”结构,统计求和靠它

awk 是三剑客里门槛最高的,但也最能打。日常用得最多的还是「取列 + 简单筛选」,把这块练熟,八成场景就拿下了。剩下那些花哨的脚本写法,用到了再查也不迟。

grep、sed、awk 三篇到这全齐活了。文本处理这套组合拳,练熟了在 Linux 上能省下大把时间。

那就把三剑客都招呼上,开干吧。

更多推荐

章节目录