引言
一个不显眼的技能组合能省掉大量「写脚本」时间:sed 处理行、awk 处理字段、jq 处理 JSON、grep 找目标——再用管道串起来。这些工具的共同哲学是「数据流」:每个工具读一行处理一行,输出给下一个。本文按工具逐个讲透,再给 10 个真实场景的管道写法。
前置:/regex-deep-dive/(sed/grep 的正则)、/unicode-encoding-guide/(编码陷阱)。
目录
- 1. 数据流哲学:管道与工具链
- 2. grep / ripgrep:精准搜索
- 3. sed:流式文本编辑
- 4. awk:字段处理语言
- 5. jq:JSON 处理
- 6. sort / uniq / wc:统计组合
- 7. cut / paste / tr:列与字符
- 8. xargs 与并行执行
- 9. 10 个实战管道场景
- 10. 一行式速查表
- 延伸阅读
1. 数据流哲学:管道与工具链
核心模型:每个命令 = 纯函数(stdin → 处理 → stdout),用 | 串联:
cat access.log | grep '500' | awk '{print $1}' | sort | uniq -c | sort -rn
管道设计原则:
| 原则 | 说明 |
|---|---|
| 单工具单职责 | 一个命令只做一件事 |
| 流式不落盘 | 中间不写文件,内存里流过 |
| 无副作用 | 不改源文件(sed -i 除外) |
| 尽早过滤 | grep 放最前省后续工作量 |
心智:管道 = 数据流水线,每个环节窄而快。先想「数据从哪来、要变成什么」再拼工具。
2. grep / ripgrep:精准搜索
grep 基础:
grep 'error' app.log # 搜索
grep -i 'warn' app.log # 忽略大小写
grep -n 'error' app.log # 显示行号
grep -v 'debug' app.log # 反选(排除)
grep -c 'error' app.log # 计数
grep -r 'pattern' src/ # 递归目录
grep -l 'pattern' src/*.py # 只列文件名
grep -A2 -B1 'error' app.log # 上下文各 2/1 行
ripgrep(rg,现代替代,快 10 倍):
rg 'TODO|FIXME' src/ # 默认递归 + 忽略 gitignore
rg -t py 'def main' # 只搜 Python
rg --stats 'error' log # 附统计
rg -uu 'hidden' # 包含隐藏文件
正则注意:默认 grep 用基础正则(BRE)——+ ? 需转义 \+ \?;用 grep -E(ERE)或 rg 免转义。
| 场景 | 命令 |
|---|---|
| 快速找关键词 | rg 'kw' dir/ |
| 统计出现行数 | grep -c pattern file |
| 只看文件名 | rg -l pattern |
| 排除二进制 | rg -t 指定类型 |
3. sed:流式文本编辑
sed 基础(s 替换 + 地址范围):
sed 's/foo/bar/' file # 每行第一个 foo → bar
sed 's/foo/bar/g' file # 全部替换(g)
sed -i 's/foo/bar/' file # 就地修改(注意 -i 改原文件!)
sed -n '5p' file # 只打印第 5 行
sed -n '1,10p' file # 打印 1-10 行
sed -n '10,20d' file # 删除 10-20 行(打印其余)
sed '/^#/d' config # 删除注释行
sed 's/^/ /' file # 每行加两空格缩进
地址匹配:
sed -n '/error/p' file # 打印含 error 的行(等价 grep)
sed '/start/,/end/d' file # 删 start~end 范围
多用例:模板替换、去尾空格、批量改路径分隔符、日志清洗。
记忆:sed 三板斧 = s(替换)、p(打印)、d(删除)+ 地址定位。加
-n只打印被选中的行。
4. awk:字段处理语言
awk 处理「列」——默认按空白/制表符切字段,$1 $2 ... $0(整行):
awk '{print $1}' file # 第一列
awk '{print $1, $NF}' file # 第一列和最后一列
awk -F',' '{print $2}' data.csv # 按逗号切分
awk '$3 > 100' file # 条件过滤(第3列>100)
awk 'NR >= 2 {print $0}' file # 跳过标题行
awk 程序结构(BEGIN 初始化,主块逐行,END 汇总):
awk 'BEGIN{sum=0} {sum += $3} END{print "总合:", sum}' sales.txt
awk 'BEGIN{max=0} {if ($2 > max) max = $2} END{print "最大:", max}' data
统计出现次数:
awk '{count[$1]++} END{for (k in count) print k, count[k]}' access.log
| 需求 | awk 写法 |
|---|---|
| 取列 | $n / $NF(最后列) |
| 自定义分隔 | -F',' 或 FS="," |
| 数值条件 | $2 > 100 |
| 累计 | sum += $n |
| 统计分组 | 数组 count[k]++ |
| 内置变量 | NR(行号) NF(字段数) FILENAME |
记忆:awk = 迷你语言:
条件 {动作}逐行执行,END块做汇总,数组当字典用。
5. jq:JSON 处理
jq 是 JSON 的 awk——查询、转换、管道:
jq '.name' user.json # 取字段(含引号)
jq -r '.name' user.json # 原始字符串(去引号)
jq '.users[]' list.json # 数组遍历
jq '.users[] | select(.age > 30)' list # 过滤
jq '.[0].name' list.json # 索引
jq '.users | length' list.json # 长度
jq 'keys' obj.json # 键列表
管道与转换:
jq '.users | map(.name)' list.json # 提取所有 name
jq 'group_by(.dept) | map({dept: .[0].dept, n: length})' emp.json
jq '{total: .items | length, sum: (.items | map(.price) | add)}' cart.json
jq -c '.[] | {id, name}' big.json > compact.ndjson # 转新行分隔 JSON
与管道组合(API 处理):
curl -s 'https://api.github.com/users/xxx/repos' | jq '.[] | .name'
| 场景 | 写法 |
|---|---|
| 取嵌套字段 | .a.b.c |
| 遍历过滤 | .arr[] | select(.x > 1) |
| 变换结构 | {k: .v} / map(...) |
| 求和 | .arr | map(.v) | add |
| 校验 JSON | jq empty file(无输出=合法) |
| 格式化 | jq . file(美化缩进) |
记忆:jq 的
|与 shell 同哲学——每个.x/map是数据变换,select过滤,{...}重构。
6. sort / uniq / wc:统计组合
sort file # 排序
sort -n file # 数值排序(不是字典序!)
sort -rn file # 数值倒序
sort -t',' -k2 file # 按第2列排序
uniq -c file # 去重并计数(必须已 sort!)
uniq -d file # 只显示重复行
wc -l file # 行数
wc -w file # 单词数
wc -c file # 字节数
经典 Top-N(访问量统计):
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10
# 取IP列 去重计数 次数倒序 取前10
注意:uniq 只合并相邻重复行——必须 sort 后再用。
组合拳:取字段(awk)→ 去重计数(sort|uniq -c)→ 排序(sort -rn)→ 截取(head)——这是日志分析四件套。
7. cut / paste / tr:列与字符
cut -d',' -f1,3 file.csv # 按逗号取第1、3列
cut -c1-10 file # 取每行前10字符
paste -d',' a.txt b.txt # 按行合并两个文件(列拼接)
tr 'a-z' 'A-Z' < file # 大小写转换
tr -d '\r' < win.txt > unix.txt # 删回车(\r)转 Unix 行尾
tr -s ' ' < file # 压缩连续空格
tr '\n' ',' < list.txt # 行转逗号分隔
行尾转换(跨平台经典):
sed 's/\r$//' win.txt > unix.txt # 或
tr -d '\r' < win.txt > unix.txt
| 需求 | 命令 |
|---|---|
| 取列 | cut -d',' -f1 |
| 合并文件列 | paste -d',' a b |
| 替换字符集 | tr 'set1' 'set2' |
| 压缩空白 | tr -s ' ' |
| 删除字符 | tr -d 'x' |
8. xargs 与并行执行
xargs:把 stdin 变成命令参数(管道最后一步常用):
find . -name '*.log' | xargs grep 'error' # 一堆文件里搜
ls *.txt | xargs -n1 wc -l # 每个文件单独执行
cat urls.txt | xargs -n1 curl -O # 逐个下载
find . -name '*.tmp' | xargs rm # 批量删除
并行(-P):
find . -name '*.jpg' | xargs -P8 -I{} convert {} {}.webp # 8 并行
cat urls.txt | xargs -P4 -I{} curl -s {} -o {}.html # 4 并发下载
| 参数 | 含义 |
|---|---|
-n1 | 每参数一个命令 |
-I{} | 占位符模式({} 代换每个输入) |
-P4 | 4 个并行进程 |
-d'\n' | 按行分隔(含空格文件名安全) |
安全提示:文件名含空格/换行时用
find -print0 | xargs -0,防参数错乱。
9. 10 个实战管道场景
1. 日志错误 Top 错误类型:
grep 'ERROR' app.log | awk '{print $5}' | sort | uniq -c | sort -rn
2. 找出访问量最大的 5 个 IP:
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -5
3. 500 错误来源路径 Top:
grep ' "500 ' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head
4. 统计每种 HTTP 状态码数量:
awk '{print $9}' access.log | sort | uniq -c
5. 进程内存 Top 5:
ps aux | awk '$6>0 {print $6, $11}' | sort -rn | head -5
6. 找出 5 分钟内修改的文件:
find . -mmin -5 -type f | head
7. 从 JSON 提取字段写入 CSV:
jq -r '.[] | [.name, .age] | @csv' users.json > out.csv
8. 合并多个日志并去重统计:
cat a.log b.log | sort | uniq -c
9. 删除所有 .tmp 文件:
find . -name '*.tmp' -type f -delete # 或
find . -name '*.tmp' -type f | xargs rm -f
10. 文本文件行数 + 最大行长度:
wc -l file.txt && awk '{if (length($0)>m) m=length($0)} END{print m}' file.txt
10. 一行式速查表
| 需求 | 一行命令 |
|---|---|
| 搜索 | rg 'kw' dir/ |
| 替换全部 | sed -i 's/a/b/g' f |
| 取列 | awk '{print $1,$NF}' f |
| JSON 取字段 | jq -r '.a.b' f |
| 计数 | sort f | uniq -c |
| Top-N | sort | uniq -c | sort -rn | head -n |
| 行数 | wc -l f |
| 去回车 | tr -d '\r' < f |
| 批量执行 | find ... | xargs -P4 ... |
| 转 CSV | jq -r '.[] | [.k] | @csv' |
一句话记忆:grep 找、sed 改、awk 切列、jq 处理 JSON、sort+uniq 统计、xargs 批量——全部数据流,先 grep 后统计,中间不落盘。
延伸阅读
- /regex-deep-dive/ — 工具背后的正则引擎
- /unicode-encoding-guide/ — 编码与行尾陷阱
- /serialization-formats-compare/ — jq 处理的 JSON 格式全景
- /dsl-design/ — awk 本身就是一门 DSL
- [[devops]] — 运维排查的数据流工具
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。