Linux 文本处理三剑客:grep、sed、awk 实战指南¶
前言¶
在 Linux 运维和开发中,80% 的日常工作都围绕文本处理展开:分析日志、提取数据、批量修改配置、格式化输出。grep、sed、awk 这三个工具构成了文本处理的核心武器库——它们各有擅长,组合使用威力无穷。
本文不是命令手册(手册看 man),而是聚焦实战场景,帮你建立「看到问题 → 选择工具 → 写出解法」的思维链路。
三句话记住分工
grep:从文本中找出符合条件的行sed:对文本做替换、删除、插入操作awk:对结构化数据做计算和格式化
grep:搜索过滤¶
基础¶
grep "error" app.log # 搜索包含 error 的行
grep -i "error" app.log # 忽略大小写
grep -v "debug" app.log # 排除包含 debug 的行
grep -n "error" app.log # 显示行号
grep -c "error" app.log # 计数
grep -r "TODO" /opt/project/ # 递归搜索目录
上下文控制¶
grep -A 3 "error" app.log # 显示匹配行 + 后 3 行(After)
grep -B 3 "error" app.log # 显示匹配行 + 前 3 行(Before)
grep -C 3 "error" app.log # 显示匹配行 + 前后各 3 行(Context)
正则表达式¶
grep -E "error|warning|critical" app.log # 扩展正则(或)
grep -E "^2026-07-20" app.log # 以日期开头
grep -E "PID: [0-9]+" app.log # 匹配数字
grep -E "192\.168\.1\.[0-9]+" access.log # 匹配 IP 段
grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" access.log | sort | uniq -c | sort -rn # 统计 IP 访问量
高频实战¶
# 排除注释和空行,查看有效配置
grep -v "^#" /etc/nginx/nginx.conf | grep -v "^$"
# 查看 5xx 错误
grep -E " 50[0-9] " /var/log/nginx/access.log
# 查看最近 100 行中的错误
tail -100 /var/log/app.log | grep -i error
# 统计每个状态码的请求数
grep -oE ' [0-9]{3} ' access.log | sort | uniq -c | sort -rn
sed:流编辑器¶
替换(最常用)¶
sed 's/old/new/' file.txt # 替换每行第一个匹配
sed 's/old/new/g' file.txt # 替换每行所有匹配
sed 's/old/new/2' file.txt # 替换每行第二个匹配
sed 's/old/new/g' file.txt # 打印到屏幕(不修改文件)
sed -i 's/old/new/g' file.txt # 直接修改文件(危险!)
sed -i.bak 's/old/new/g' file.txt # 备份后再修改(推荐)
正则替换¶
# 删除行首空格
sed 's/^[[:space:]]*//' file.txt
# 删除行尾空格
sed 's/[[:space:]]*$//' file.txt
# 替换 IP 地址
sed -E 's/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/REDACTED/g' access.log
# 给行号加前缀
sed = file.txt | sed 'N;s/\n/ /'
增删改行¶
# 删除第 3 行
sed '3d' file.txt
# 删除 3 到 5 行
sed '3,5d' file.txt
# 删除空行
sed '/^$/d' file.txt
# 删除包含 "debug" 的行
sed '/debug/d' file.txt
# 在第 3 行后插入
sed '3a\new line' file.txt
# 在第 3 行前插入
sed '3i\new line' file.txt
# 替换第 3 行整行
sed '3c\new content' file.txt
# 打印第 5 到 10 行
sed -n '5,10p' file.txt
高频实战¶
# 一键修改配置文件(端口从 8080 改为 9090)
sed -i.bak 's/port=8080/port=9090/g' /etc/myapp/config.ini
# 清理 CSV 中的多余引号
sed 's/^"//;s/"$//' data.csv
# 在 Dockerfile 的 CMD 之前添加一行
sed -i '/^CMD/i RUN echo "build step"' Dockerfile
# 提取日志的第 100 到 200 行
sed -n '100,200p' /var/log/app.log
awk:结构化数据处理¶
awk 程序的三个部分¶
字段处理¶
$0 = 整行,$1 = 第一个字段,$2 = 第二个字段……NF = 字段总数,NR = 行号:
# 打印第 1 和第 3 列
awk '{print $1, $3}' data.txt
# 打印最后一列
awk '{print $NF}' data.txt
# 打印倒数第二列
awk '{print $(NF-1)}' data.txt
# 设置分隔符
awk -F: '{print $1, $7}' /etc/passwd # 冒号分隔
awk -F',' '{print $2}' data.csv # 逗号分隔
awk -F'[ ,]+' '{print $1, $2}' data.txt # 空格或逗号分隔
条件过滤¶
# 第 3 列 > 100 的行
awk '$3 > 100' data.txt
# 包含 "error" 的行
awk '/error/' app.log
# 第 1 列等于 "nginx" 且第 3 列 > 5
awk '$1 == "nginx" && $3 > 5' data.txt
# 第 5 列不是空
awk '$5 != ""' data.txt
计算¶
# 求第 3 列的总和
awk '{sum += $3} END {print sum}' data.txt
# 求第 3 列的平均值
awk '{sum += $3; count++} END {print sum/count}' data.txt
# 找出第 3 列的最大值
awk 'max < $3 {max = $3} END {print max}' data.txt
# 按第 1 列分组求和
awk '{sum[$1] += $3} END {for (k in sum) print k, sum[k]}' data.txt
格式化输出¶
# 对齐打印
awk '{printf "%-20s %10s\n", $1, $2}' data.txt
# 用制表符分隔
awk -v OFS='\t' '{print $1, $2, $3}' data.txt
生产环境实战案例¶
案例 1:Nginx 日志分析¶
# 访问量 Top 10 IP
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
# 状态码分布
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
# 响应时间超过 1 秒的请求
awk '$NF > 1 {print $0}' /var/log/nginx/access.log
# 每个小时的请求量
awk '{print substr($4,2,14)}' access.log | cut -d: -f1 | sort | uniq -c
案例 2:从 /etc/passwd 提取信息¶
# 列出所有用户名
awk -F: '{print $1}' /etc/passwd
# 列出 Shell 为 /bin/bash 的用户
awk -F: '$7 == "/bin/bash" {print $1}' /etc/passwd
# UID >= 1000 的普通用户数
awk -F: '$3 >= 1000 {count++} END {print count}' /etc/passwd
案例 3:监控脚本¶
#!/bin/bash
# 内存使用超过 80% 告警
free -m | awk 'NR==2 {
used=$3; total=$2;
pct=used/total*100;
if (pct > 80) printf "WARNING: Memory usage %.1f%%\n", pct
}'
案例 4:批量重命名¶
# 将所有 .JPG 改为 .jpg
ls *.JPG | sed 's/\.JPG$//' | while read name; do
mv "${name}.JPG" "${name}.jpg"
done
案例 5:配置漂移检查¶
# 对比两台服务器的 nginx 配置差异(排除注释和空行)
diff <(ssh srv1 "grep -v '^#' /etc/nginx/nginx.conf | grep -v '^$'") \
<(ssh srv2 "grep -v '^#' /etc/nginx/nginx.conf | grep -v '^$'")
工具选择决策树¶
flowchart TD
A[文本处理需求] --> B{做什么?}
B -->|搜索/过滤| C[grep]
B -->|替换/删除/插入| D[sed]
B -->|计算/分组/格式化| E[awk]
C --> C1{需要上下文?}
C1 -->|是| C2[grep -A/-B/-C]
C1 -->|否| C3[grep 基础]
D --> D1{修改原文件?}
D1 -->|是| D2[sed -i.bak<br>先备份!]
D1 -->|否| D3[sed 管道处理]
E --> E1{数据是结构化的?}
E1 -->|列分隔| E2[awk -F 指定分隔符]
E1 -->|需要计算| E3[awk 内置算术]
style C fill:#dbeafe,stroke:#2563eb
style D fill:#fef3c7,stroke:#d97706
style E fill:#d1fae5,stroke:#059669 正则表达式速查¶
| 模式 | 含义 | 示例 |
|---|---|---|
^ | 行首 | ^# 以 # 开头 |
$ | 行尾 | ;$ 以 ; 结尾 |
. | 任意单个字符 | h.t 匹配 hat, hot, hit |
* | 前一个字符重复 0 次或多次 | ab*c 匹配 ac, abc, abbc |
+ | 前一个字符重复 1 次或多次(需 -E) | ab+c 匹配 abc, abbc |
? | 前一个字符可选(需 -E) | colou?r 匹配 color, colour |
[] | 字符集 | [0-9] 数字,[a-z] 小写字母 |
[^] | 排除字符集 | [^0-9] 非数字 |
\| | 或(需 -E) | error\|warning |
() | 分组(需 -E) | (ab)+ 匹配 ab, abab |
{n,m} | 重复 n 到 m 次(需 -E) | [0-9]{2,4} 2~4 位数字 |
\b | 单词边界 | \bword\b 精确匹配 word |
\s | 空白字符(需 -E 或 [[:space:]]) | \s+ 一个或多个空白 |
下一步学习¶
| 方向 | 教程 |
|---|---|
| Shell 脚本 | Shell 基础 — 用三剑客构建自动化脚本 |
| 常用命令 | 常用命令指南 — sort/uniq/cut 等配套工具 |
| 系统监控 | 系统监控 — 监控脚本实战 |
| 日志管理 | 日志管理 — 日志分析与清理 |
总结¶
文本处理三剑客是 Linux 运维的「万能瑞士军刀」:
grep:快速定位,-A/-B/-C查看上下文,-oE提取模式sed:批量替换用-i.bak先备份,/pattern/d删除行,/pattern/a追加行awk:结构化数据用-F设分隔符,{sum+=$N}做计算,END {print}出结果
三个工具不是竞争关系——最强大的用法是管道串起来:
这就是命令行之美:每个工具只做一件事,但组合起来无所不能。 🚀