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 中筛选 ERRORcost>100 的行并输出时间与用户字段。
3) 将 app.loguser=xxx 统计并按次数降序输出。

提示参考:

# 练习1参考思路
awk '{print $7}' access.log | sort | uniq -c | sort -nr | head -10