5.4.4 管道与组合命令设计
管道与组合命令设计#
管道(|)将前一个命令的标准输出作为后一个命令的标准输入,是文本处理与自动化的核心。本节通过结构化设计、示例与排错,帮助你构建高可读、可维护、可复用的组合命令。
原理草图#
环境准备与工具可用性检查#
多数发行版默认自带 grep/sed/awk/sort/uniq/cut。可用性检查与版本确认:
# 工具存在性检查
command -v grep sed awk sort uniq cut >/dev/null && echo "tools ok"
# 版本检查(排障时确认功能支持)
grep --version | head -1
awk --version | head -1
sed --version | head -1
设计原则与关键命令解释#
- 单一职责:每个命令只做过滤/转换/聚合之一。
- 尽早过滤:先缩小数据量,降低后续开销。
- 明确字段:使用
-F(awk分隔符)、-d(cut分隔符)、-OFS(awk输出分隔符)。 - 可读性优先:使用续行
\、加注释。
命令解释示例:
# 解释:
# grep -E: 使用扩展正则
# awk -F: 指定分隔符
# sort -nr: 按数值逆序
grep -E "ERROR|WARN" app.log \
| awk -F' ' '{print $1, $2, $5}' \
| sort
常用组合模式与完整示例#
1) 过滤 + 字段提取(带输入示例与预期输出)
# 示例输入(app.log)
# 2024-08-01 10:01:02 INFO user=alice cost=12
# 2024-08-01 10:01:03 ERROR user=bob cost=50
grep "ERROR" app.log | awk '{print $1,$2,$4,$5}'
# 预期输出:
# 2024-08-01 10:01:03 user=bob cost=50
2) 统计 + 排序(访问 IP Top5)
# access.log 中第1列为客户端IP
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -5
# 解释:uniq -c 统计重复,sort -nr 按计数逆序
3) 替换 + 聚合(统一路径格式后统计)
# 将 "GET /api" 统一为 "/api" 再统计
sed 's#GET /#/#' access.log \
| awk '{print $7}' \
| sort | uniq -c | sort -nr | head -10
4) 多条件过滤(结合 grep 与 awk)
# 先筛出 WARN,再按数值字段过滤
grep "WARN" app.log | awk '$5>100 {print $0}'
管道中的错误处理与排错#
1. 捕获任一环节失败
set -o pipefail
grep "ERROR" app.log | awk '{print $1}' | sort || {
echo "pipeline failed" >&2
exit 1
}
2. 常见问题排查
- 无输出:检查输入文件是否存在、大小是否为 0。
- 字段错位:检查分隔符是否一致(空格/制表符/冒号)。
- 排序异常:数值排序需 sort -n,字符串默认字典序。
排查示例:
# 查看文件是否为空
ls -lh app.log
# 查看分隔符实际情况(显示TAB为^I)
sed -n '1,3p' app.log | cat -A
# 用 awk 输出字段数量
awk '{print NF}' app.log | head
性能与稳定性建议#
- 能用 awk 一次完成就不要拆:
# 统计 ERROR 中 user 字段出现次数
awk '/ERROR/ {for(i=1;i<=NF;i++) if($i ~ /^user=/) {cnt[$i]++}} \
END{for(k in cnt) print k,cnt[k]}' app.log | sort -k2 -nr
- 大文件建议使用 head 截断
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -20
典型组合实战(可直接执行)#
1) 统计最近 1 小时错误日志数量
# 假设日志时间在行首,格式:YYYY-MM-DD HH:MM:SS
awk -v t="$(date -d '1 hour ago' '+%Y-%m-%d %H:%M:%S')" \
'$0>=t && /ERROR/ {c++} END{print c+0}' app.log
2) 查看进程资源消耗 Top5
ps aux | awk 'NR>1 {print $3,$4,$11}' | sort -k1 -nr | head -5
# 输出格式:CPU% MEM% 进程名
3) 提取 Nginx 状态码分布
awk '{print $9}' access.log | grep -E '^[0-9]{3}$' | sort | uniq -c | sort -nr
练习题#
1) 统计 access.log 中访问次数最多的前 10 个 URL。
2) 从 app.log 中筛选 ERROR 且 cost>100 的行并输出时间与用户字段。
3) 将 app.log 中 user=xxx 统计并按次数降序输出。
提示参考:
# 练习1参考思路
awk '{print $7}' access.log | sort | uniq -c | sort -nr | head -10