Shell脚本精读 · S10-01 | 何时用 Shell、何时用 awk/sed:分工原则
📅 2026/7/8 9:18:25
👁️ 阅读次数
📝 编程学习
模块: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/passwd2. 一张选型表
| 你想做的事 | 优先工具 | Shell 做什么 |
|---|---|---|
| 文件在不在、权限、复制移动 | Shell[ -f ]cpmv | 全流程 |
| 日志里有没有 ERROR | grep-q/ 管道 | if grep ...; then |
删掉行首#注释 | sed | 调 sed,检查$? |
把a=b改成export a=b | sed | 输入输出重定向 |
| 统计第三列之和 | awk | 传文件路径、处理退出码 |
| 批量重命名 50 个文件 | Shellfor+mv | 循环与路径 |
| 从 JSON 取字段 | jq(若环境有) | 胶水;别硬用 awk 解析 JSON |
| 并行下载 3 个 URL | Shell&+wait(S09-04) | 编排 |
3. Shell:编排与胶水
适合留在 Bash 的:
set -euo pipefail、参数检查、usagefor 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 | 聚合统计sum、count |
| 简单提取 | 结构化数据 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读法:
- grep:只要 ERROR 行
- awk:取前两列
- sort / uniq / sort:Shell 外置命令,仍是胶水链
set -o pipefail(S09-02):grep无匹配时整条链应失败,别被后面sort掩盖。
8. 反模式(读脚本时警惕)
| 反模式 | 问题 | 更好 |
|---|---|---|
for line in $(cat f) | 拆词、丢格式 | while read -r或awk |
超长$(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. 读脚本的三问
- 这段是在「调命令」还是在「算文本」?
→ 算文本:找 grep/sed/awk 边界。 - 失败谁负责?
→ Shell:set -e、pipefail、if cmd。 - 数据规模?
→ 大文件:避免$(cat huge)进变量;用流式管道 / awk 一行流。
读脚本检查清单
- 复杂列操作是否该用awk却用
cut+while硬拼? - 是否只需grep -q却
grep | wc -l? - sed -i是否有备份、是否检查失败?
- 管道左端grep/awk失败会不会被sort盖住(pipefail)?
- JSON/XML 是否误用 awk 硬解析?
练习
判断题
- Shell 不适合做「遍历目录 + 调外部命令」的编排。
- 判断日志是否含 ERROR,优先
grep -q。 - 把文件中所有
foo换成bar,优先 sed。 - 求 CSV 第三列数值总和,优先 awk。
- 专栏要求你把 awk 语法从头到尾背下来才能写脚本。
- 错(这正是 Shell 强项)。
- 对。
- 对。
- 对。
- 错(S10-03 学「胶水式一键调用」即可)。
选型题
各题选Shell / grep / sed / awk(主工具,可多选「Shell + 工具」):
- 检查
config.ini是否包含enabled=yes - 删除
notes.txt里所有空行 - 打印
sales.csv中金额(第 4 列)大于 1000 的行 - 对
reports/*.log逐个调用gzip - 统计
access.log中 HTTP 状态码 404 的出现次数(状态码在第 9 列)
- grep(+ Shell 判
$?) - sed(+ Shell 重定向/备份)
- awk
- Shell
for - 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 | ...管道。
编程学习
技术分享
实战经验