暗色模式

Linux 文本处理三剑客实战:grep、sed、awk 高效处理日志与配置

技术教程
2026-08-03
7
0

三剑客是什么

Linux 运维中有一组几乎每天都用得上的经典工具组合:grep、sed、awk,合称「文本处理三剑客」。它们各自专精一个环节,用管道串起来就能完成从检索、编辑到统计分析的完整数据流:

工具定位一句话概括
grep检索从文件或流中过滤出匹配的行
sed编辑对文本流做替换、删除、插入等编辑
awk分析字段切分并做统计、格式化输出

它们都是 POSIX 标准工具,任何 Linux 发行版开箱即用,是脚本自动化与日志排查的基础设施。本文所有命令都在 Ubuntu 24.04 的真实服务器上验证过,截图均为实际输出。

版本现状速览

工具演示环境(Ubuntu 24.04)最新上游版本发布要点
GNU grep3.113.12(2025-04-10)修复 3.11 引入的「目录含 10 万条目时报 Operation not supported」等 bug
GNU sed4.94.10(2026-04-21)修复 -i 处理超 2GB 行、--follow-symlinks -i 的 TOCTOU 竞态
GNU awk (gawk)5.2.15.4.1(2026)常规演进,字段分析功能稳定

发行版自带版本通常落后上游一两个小版本,但不影响本文命令的可用性。

grep:把日志里的「噪音」过滤掉

grep 的核心工作只有一件:按模式保留(或排除)匹配的行。运维中最常见的场景就是翻日志——几百 MB 的日志里找出 error,用编辑器翻是不可能的,grep 一次搞定。

高频参数速查

grep "error" app.log            # 基本检索,输出匹配行
grep -E "error|failed" app.log  # 扩展正则(-E 或 egrep),| 表示或
grep -i "error" app.log         # -i 忽略大小写
grep -v "debug" app.log         # -v 反选,输出不匹配的行
grep -c "error" app.log         # -c 只输出匹配行数
grep -n "error" app.log         # -n 输出行号
grep -o "timeout=\w*" app.log   # -o 只输出匹配部分(提取字段很好用)
grep -A2 -B2 "exception" app.log # 输出匹配行的上 2 行、下 2 行上下文
grep -r "TODO" src/             # -r 递归目录
grep --include="*.log" -r "err" /var/log/  # 限定文件类型

实战:从系统日志中检索错误

在服务器上直接对 /var/log/syslog 实操:

grep -c -i error /var/log/syslog
grep -n -i failed /var/log/syslog | tail -2
grep -i error /var/log/syslog | tail -2

第一条统计错误出现次数,第二条带行号看「failed」的具体位置,第三条看最近一条错误。结果如下:

grep 检索实战输出

常见坑:PCRE 的 \d\w

\d\w 这类「Perl 风格」简写只有 grep 的 PCRE 模式(-P)才支持。普通模式(默认/-E)里 \d 无效,需要写成 [0-9][[:digit:]]

grep -P "\d+\.\d+\.\d+\.\d+" access.log   # -P 才支持 \d
grep -E "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" access.log  # 等价的 ERE 写法

另外注意 GNU grep 3.11 起 -P 模式下的 \w\b 恢复为 ASCII 语义(中文、日文等宽字符不再算「单词字符」),3.8 之前的行为曾短暂不一致,写脚本时不要依赖这些边界行为。

sed:不动编辑器的「流式编辑」

sed(Stream Editor)像一条传送带:文本流经过它时,按规则被替换、删除或插入。最常用的三个动作:

sed 's/old/new/' file          # 替换每行第一个匹配
sed 's/old/new/g' file         # g 全局替换,替换所有匹配
sed 's/old/new/2' file         # 只替换每行第 2 个匹配
sed -i 's/old/new/g' file      # -i 原地修改文件(慎用,先备份)
sed -n '5,10p' file            # 只打印 5~10 行(-n 关闭默认输出)
sed '3d' file                  # 删除第 3 行
sed '/^#/d' file               # 删除所有以 # 开头的注释行
sed '1i 内容' file             # 在第 1 行之前插入
sed '30a 内容' file            # 在第 30 行之后追加
sed -E 's/([0-9]{3})/(\1)/g'   # -E 扩展正则 + \1 反向引用

-np 的组合要特别记住:默认 sed 会把每一行都打印一遍,-n 关掉默认输出后,只有命中的 p 才打印——这是「只抽几行看」的标准姿势。

实战:批量修改配置文件

改服务器配置时经常要「批量替换 + 顺手插入一行」。为了避免动到线上 sshd_config,先复制到 /tmp 演示(真实操作前也应该先备份):

cp /etc/ssh/sshd_config /tmp/sshd_demo.conf
sed -i 's/^#PermitRootLogin.*/PermitRootLogin prohibit-password/' /tmp/sshd_demo.conf
grep -n PermitRootLogin /tmp/sshd_demo.conf
sed -i '1i # sed-demo: keep-alive on' /tmp/sshd_demo.conf
sed -n '1,3p' /tmp/sshd_demo.conf

第一条命令用 ^# 锚定「被注释的行」,.* 吃掉整行再整体替换——这是 sed 改配置文件的经典写法(只改注释掉的那一行,不影响已生效的配置)。结果如下:

sed 编辑实战输出

-i 的安全习惯

-i 是原地修改,没有「撤销」。可靠做法:

cp file file.bak && sed -i 's/old/new/g' file   # 先备份
sed -i.bak 's/old/new/g' file                    # 更省事:自动生成 file.bak

sed 4.10 还修复了 sed --follow-symlinks -i 的 TOCTOU 竞态(攻击者可利用符号链接替换让 sed 读入恶意内容),普通用法无感,但别把 -i 用在不受信任目录里的符号链接上。

awk:按字段「切」数据并统计

awk 是三者里最强的:它把每一行按分隔符切成字段,再对字段做计算与格式化输出。读日志、解析配置、算统计数据,awk 一条命令抵十行脚本。

核心概念:字段、分隔符、BEGIN/END

awk '{print $1}' file            # 打印每行第 1 个字段(默认按空白切分)
awk '{print $1, $NF}' file       # $NF 是最后一个字段,$2 $3 ... 依此类推
awk -F: '{print $1, $3}' file    # -F 指定分隔符(这里按冒号切)
awk '$3 > 100 {print $1}' file   # 条件过滤:第 3 字段大于 100
awk 'BEGIN{sum=0} {sum+=$2} END{print sum}' file  # BEGIN 开头执行一次,END 结束执行一次
awk '{count[$1]++} END{for (k in count) print count[k], k}' file  # 按第 1 字段分组计数

要点:BEGIN{} 在读取第一行前执行,END{} 在所有行处理完后执行——统计类需求全靠这两个块

实战:解析 /etc/passwd 与统计日志

/etc/passwd 用冒号分隔,正好演示 -F 切字段;系统日志则演示分组计数:

awk -F: '$3 >= 1000 {print $1, "uid=" $3, $7}' /etc/passwd
awk '{count[$3]++} END {for (p in count) print count[p], p}' /var/log/syslog | sort -rn | head -4
grep Accepted /var/log/auth.log | awk '{print $9}' | sort | uniq -c | sort -rn

三条命令分别做到:列出 UID≥1000 的普通用户、统计 syslog 里各进程的日志条数、统计 SSH 登录来源 IP。结果如下:

awk 分析实战输出

注意第三条:awk 不认识 auth.log 每行的第 9 个字段是 IP——它是靠字段位置工作的。日志格式一变,字段序号就要跟着调,这是用 awk 的唯一心智负担。

三剑客协同:一条管道完成日志分析

三把工具单独用只是热身,真正的威力在管道组合——各自只做一步,| 串起来:

# 例 1:统计错误日志里出现最多的进程
grep -i error /var/log/syslog | awk '{print $3}' | sort | uniq -c | sort -rn | head -5

# 例 2:找出访问量前 10 的 IP(access.log,格式: IP - - [时间] "GET ..." 200 1234)
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10

# 例 3:把 access.log 里 404 请求的行号抽出来检查
grep -n '" 404 ' access.log | sed 's/:.*//' | head -20

# 例 4:计算接口平均响应时间(字段 10 为耗时 ms)
awk '$9 == 200 {sum += $10; n++} END {print "avg:", sum/n, "ms"}' access.log

设计思路很固定:grep 负责筛行 → awk 负责切字段 → sort/uniq 负责排序去重 → head 负责截取。养成把「先试通小样、再加参数」的习惯(比如先不加 | head 跑一遍看全貌),排查会顺畅很多。

延伸:新一代的 rg(ripgrep)要不要用?

如果觉得 grep 搜大目录太慢,试试 ripgrep(rg)——Rust 写的检索工具,近年最成功的 grep 替代者。实测性能差异巨大(来源见文末):

  • 13GB 单文件搜索:rg 1.04s vs GNU grep 6.58s
  • 25 万文件的大型 monorepo:rg 2.3s vs grep 45.2s(约 20 倍)
  • 默认自动跳过 .gitignore、二进制文件、.git/ 目录,无需手动加 --exclude

但 grep 依然不可替代,三剑客中 grep 的位置不会被 rg 拿走

  1. 管道场景没差别ps aux | grep ssh 这类 stdin 过滤,grep 又快又普适
  2. POSIX 与脚本兼容:rg 不保证 POSIX 行为,老脚本、sh -c 里用 grep 最稳
  3. 零依赖:任何发行版都预装,嵌入式/最小化系统只有 grep

实践建议:日常搜代码、搜大日志文件用 rg;写脚本、处理管道流、跑在别人的服务器上,继续用 grep。命令是相通的,rg -irg -crg -n 与 grep 同参数同直觉。

小结

  • grep 过滤-i-v-c-n-o-A/-B-E 是最高频组合,日志排错先 grep -iE "error|fail"
  • sed 编辑s/old/new/g + -i + -n 'a,bp' 覆盖 90% 场景,-i 前先备份;
  • awk 分析:记住 -F$NFBEGIN/ENDcount[$1]++ 四板斧,统计信手拈来;
  • 管道协同:grep → awk → sort → head 是日志分析的万能流水线;
  • 大文件、大目录搜索直接上 rg,脚本场景继续 grep

把这套组合练熟,排查问题时的「翻日志十分钟」能缩短到「一条命令」。

参考资料

发表评论

暂无评论,快来抢沙发吧!