Shell脚本精读 · S10-01 | 何时用 Shell、何时用 awk/sed:分工原则

模块:S10 文本处理协作
篇号:S10-01 / 42
预计阅读:40 分钟
主线:Bash


文章目录

    • 本篇目标
    • 30 秒速览
    • 正文
      • 1. 为什么需要分工
      • 2. 一张选型表
      • 3. Shell:编排与胶水
      • 4. grep:筛行、判断存在
      • 5. sed:流式编辑(替换、删行)
      • 6. awk:按列处理与报表
      • 7. 管道里的分工
      • 8. 反模式(读脚本时警惕)
      • 9. 环境里没有 awk/sed 时
      • 10. 读脚本的三问
    • 读脚本检查清单
    • 练习
      • 判断题
      • 选型题
      • 读脚本题
    • 下一篇预告

本篇目标

建立Shell 与 grep/sed/awk的分工观:Shell 负责流程、文件、进程、退出码;专用工具负责按行/按列处理文本。能判断一段逻辑该留在 Bash、该交给谁,避免把 awk 程序整段塞进$( )或用for+cut拼复杂报表。为S10-02(grep)S10-03(sed/awk 胶水)打选型基础。


30 秒速览

  • Shell 强项:调命令、判退出码、循环文件、环境变量、管道串联。
  • grep 强项有没有筛哪些行(模式匹配)。
  • sed 强项按规则改文本(替换、删行、简单提取)。
  • awk 强项按列/字段统计、求和、格式化输出(表格、报表)。
  • 原则:Shell 当胶水;文本算法交给合适工具;别在 Bash 里手写 CSV 解析器
  • 读完脚本:先认「编排」还是「数据处理」。

正文

1. 为什么需要分工

Bash什么都能沾一点,但下列写法往往难维护:

# 反例:用纯 Shell 解析 /etc/passwd 第七列whileIFS=:read-r_ _ _ _ _ _ homedir _;do...done</etc/passwd

同样任务,awk -F:常更短、更清晰(S10-03 给一键示例)。
Shell 的价值是:决定读哪个文件、失败怎么办、结果往哪送

#!/usr/bin/env bashset-euopipefail[[-f/etc/passwd]]||exit1awk-F:'$3 >= 1000 {print $1, $6}'/etc/passwd

2. 一张选型表

你想做的事优先工具Shell 做什么
文件在不在、权限、复制移动Shell[ -f ]cpmv全流程
日志里有没有 ERRORgrep-q/ 管道if grep ...; then
删掉行首#注释sed调 sed,检查$?
a=b改成export a=bsed输入输出重定向
统计第三列之和awk传文件路径、处理退出码
批量重命名 50 个文件Shellfor+mv循环与路径
从 JSON 取字段jq(若环境有)胶水;别硬用 awk 解析 JSON
并行下载 3 个 URLShell&+wait(S09-04)编排

3. Shell:编排与胶水

适合留在 Bash 的

  • set -euo pipefail、参数检查、usage
  • for f in "$@"; do遍历文件
  • if/case分支、exit
  • 管道串联grep ... | awk ... | sort
  • 调用curl、git、make、docker等外部命令
main(){(($#>=1))||usageforlogin"$@";do[[-f"$log"]]||continueifgrep-qERROR"$log";thenreport_error"$log"fidone}

Shell 不必擅长:复杂字符串算法、大文件逐字符处理、多维统计。


4. grep:筛行、判断存在

典型

ifgrep-q'^ERROR'"$LOG";thenalertfigrep-h'^#'"$CONF"||true# 只看注释行
用 grep不必 grep
模式匹配行按第 N 列求和(用 awk)
if grep -q判断替换文本(用 sed)
多个文件同一模式复杂状态机解析

细节在S10-02-E-F、递归-r等)。


5. sed:流式编辑(替换、删行)

一行式在脚本里很常见:

sed-i.bak's/\r$//'"$file"# 去 CRLFsed'/^$/d'input.txt# 删空行sed-n'1,10p'huge.log# 只打印前 10 行
用 sed考虑 awk / 其它
单模式替换s/old/new/多列条件($3>100)
按地址删行/^#/d聚合统计sumcount
简单提取结构化数据 JSON →jq

-i原地改文件:脚本里注意备份、权限;失败要检查退出码。


6. awk:按列处理与报表

典型

# 统计 access.log 里状态码 500 的次数(示意:第 9 列为状态码)awk'$9 == 500 {c++} END {print c+0}'access.log# 打印 passwd 里 UID>=1000 的用户名与家目录awk-F:'$3 >= 1000 {print $1, $6}'/etc/passwd
用 awk用 Shell 就够
指定分隔符、字段号$1$NF整行原样cat、移动文件
END {print sum}汇总只有grep 有没有
格式化列对齐printf两三个if分支

不必为 awk 写长篇教程;脚本里多数是-F、模式、print一键调用(S10-03)。


7. 管道里的分工

grepERROR app.log\|awk'{print $1, $2}'\|sort\|uniq-c\|sort-nr

读法:

  1. grep:只要 ERROR 行
  2. awk:取前两列
  3. sort / uniq / sort:Shell 外置命令,仍是胶水链

set -o pipefail(S09-02):grep无匹配时整条链应失败,别被后面sort掩盖。


8. 反模式(读脚本时警惕)

反模式问题更好
for line in $(cat f)拆词、丢格式while read -rawk
超长$(awk '...')难调试、引号地狱awk 读文件或here-doc 程序
纯 Shell 解析 CSV逗号、引号易错awk -F,或 Python
sed 算总数awk 更合适awk '{s+=$3} END{print s}'
grep 当计算器做不到awk / bc / $(( ))

9. 环境里没有 awk/sed 时

  • 最小系统可能只有busybox子集;读脚本看 shebang 与文档。
  • 可移植脚本(S13):避免 GNU 独有扩展,或检测command -v awk
  • 专栏主线是Bash + 常见 GNU/Linux 工具链;嵌入式/极简环境另论。

10. 读脚本的三问

  1. 这段是在「调命令」还是在「算文本」?
    → 算文本:找 grep/sed/awk 边界。
  2. 失败谁负责?
    → Shell:set -epipefailif cmd
  3. 数据规模?
    → 大文件:避免$(cat huge)进变量;用流式管道 / awk 一行流

读脚本检查清单

  • 复杂列操作是否该用awk却用cut+while硬拼?
  • 是否只需grep -qgrep | wc -l
  • sed -i是否有备份、是否检查失败?
  • 管道左端grep/awk失败会不会被sort盖住(pipefail)?
  • JSON/XML 是否误用 awk 硬解析?

练习

判断题

  1. Shell 不适合做「遍历目录 + 调外部命令」的编排。
  2. 判断日志是否含 ERROR,优先grep -q
  3. 把文件中所有foo换成bar,优先 sed。
  4. 求 CSV 第三列数值总和,优先 awk。
  5. 专栏要求你把 awk 语法从头到尾背下来才能写脚本。
参考答案
  1. 错(这正是 Shell 强项)。
  2. 对。
  3. 对。
  4. 对。
  5. 错(S10-03 学「胶水式一键调用」即可)。

选型题

各题选Shell / grep / sed / awk(主工具,可多选「Shell + 工具」):

  1. 检查config.ini是否包含enabled=yes
  2. 删除notes.txt里所有空行
  3. 打印sales.csv中金额(第 4 列)大于 1000 的行
  4. reports/*.log逐个调用gzip
  5. 统计access.log中 HTTP 状态码 404 的出现次数(状态码在第 9 列)
参考答案
  1. grep(+ Shell 判$?
  2. sed(+ Shell 重定向/备份)
  3. awk
  4. Shellfor
  5. awk(或 grep 404 再 wc,但列位置明确时 awk 更准)

读脚本题

说明下面片段各自依赖什么工具完成什么分工:

forfin"$@";dosed's/\t/,/g'"$f"|awk-F,'$4 > 0 {print $1,$4}'|sort-t,-k2-nrdone
参考答案
  • Shell:遍历参数文件。
  • sed:Tab 改逗号(若已是 CSV 可能多余)。
  • awk:按逗号字段过滤第 4 列 > 0,打印第 1、4 列。
  • sort:按第 2 列数值降序(此处列与 awk 输出字段对应关系需与数据一致,读脚本时要核对)。

下一篇预告

S10-02:《grep/egrep与脚本:过滤与if grep -q》— 模式、递归、退出码与grep | ...管道。