news 2026/7/6 23:31:30

Shell脚本精读 · S09-02 | 管道与管道退出码:`pipefail` 再探

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Shell脚本精读 · S09-02 | 管道与管道退出码:`pipefail` 再探

模块:S09 进程、管道与重定向
篇号:S09-02 / 42
预计阅读:45 分钟
主线:Bash


文章目录

    • 本篇目标
    • 30 秒速览
    • 正文
      • 1. 管道是什么
      • 2. 并行,不是「先跑完再跑」
      • 3. 默认退出码:只看最后一个
      • 4. `set -o pipefail` 再探(衔接 S01-04)
      • 5. `PIPESTATUS`:逐节查退出码
      • 6. 与 `set -e` 的配合
      • 7. stderr 与管道
      • 8. 多节管道与重定向
      • 9. 读脚本时的常见模式
        • 9.1 过滤 + 统计
        • 9.2 检查中间步骤(无 pipefail 时)
        • 9.3 `| while read` 与退出码(两个问题)
        • 9.4 显式检查第一节
      • 10. 对照表
      • 11. 注意点
    • 读脚本检查清单
    • 练习
      • 判断题
      • 实操题
      • 改错题
    • 下一篇预告

本篇目标

掌握管道cmd1 | cmd2的数据流与退出码规则:默认$?只看管道最后一节set -o pipefail为何与set -e配套(S01-04)。会用PIPESTATUS检查每一节,读懂grep | awk| while read等常见组合,并避开「前面命令失败了脚本却继续」的坑。


30 秒速览

  • A | B:A 的stdout接到 B 的stdin;两命令并行执行。
  • 默认$?:等于管道最后一个命令的退出码。
  • set -o pipefail:任一命令失败 →整管道视为失败(与 S01-04 骨架一致)。
  • PIPESTATUS:数组,按顺序存管道每一节的退出码(Bash)。
  • stderr 默认不进管道;要合并 stderr 用2>&1 |或 Bash|&
  • | while read右侧常在子 shell(S07-02);与$?是不同问题。

正文

1. 管道是什么

grepERROR app.log|wc-l
部分含义
grep ...从文件筛行,结果写到stdout
|把左边 stdout接到右边 stdin
wc -l从 stdin 读入,统计行数

左边不必写文件:数据流经管道,可省临时文件。

psaux|grepnginxcataccess.log|tail-n100

2. 并行,不是「先跑完再跑」

yes|head-n3
  • yes持续输出
  • head -n 3读满 3 行后退出
  • yes可能收到SIGPIPE被终止

读脚本:管道两端同时在跑;读者提前结束时,写者可能失败(broken pipe),这在set -o pipefail下会影响$?


3. 默认退出码:只看最后一个

false|trueecho$?# 0
命令退出码
false1
true0
管道整体$?0(默认取true
grep-qNOMATCH file.txt|echookecho$?# 0 — grep 失败,但 echo 成功

读脚本陷阱:管道前面grepfindcurl失败了,只要最后一条是trueteewc成功,默认$?仍为 0


4.set -o pipefail再探(衔接 S01-04)

set-efalse|trueecho"仍会执行"# 管道整体 $? 为 0,set -e 不触发
set-euopipefailfalse|trueecho"不会执行"# 管道失败,set -e 退出
模式管道失败条件
默认最后一个命令非 0
pipefail任一命令非 0

专栏骨架set -euo pipefail的意义之一:
cmd1 | cmd2 | cmd3cmd1失败不会被cmd3的成功掩盖

关闭:set +o pipefail


5.PIPESTATUS:逐节查退出码

Bash 在管道执行后填充PIPESTATUS数组,下标从 0 起):

false|true|falseecho"whole=$?"echo"pipestatus=${PIPESTATUS[*]}"# whole=0(默认,最后 true)# pipestatus=1 0 1
set-opipefailfalse|true|falseecho"whole=$?"# 1echo"0=${PIPESTATUS[0]}"# 1echo"1=${PIPESTATUS[1]}"# 0echo"2=${PIPESTATUS[2]}"# 1

注意

  • PIPESTATUS在下一条命令执行后会被覆盖;要保存就及时赋值:
grepfoo f|sortstatus=("${PIPESTATUS[@]}")echo"grep=${status[0]}sort=${status[1]}"
  • if&&里跑管道后,PIPESTATUS仍可用(紧接的下一条语句前)。

6. 与set -e的配合

场景行为要点
set -e+ 管道管道整体失败时退出(失败定义见上)
pipefail仅最后命令失败才使管道失败
cmd || true故意吃掉失败(S04-02)
set-euopipefailgreppattern"$f"|process# grep 无匹配(退出 1)→ 整管道失败 → 脚本退出

若「无匹配不算错误」:

greppattern"$f"|process||true# 或ifgreppattern"$f"|process;then...

7. stderr 与管道

默认:只有stdout进管道;stderr仍去终端(或外层重定向)。

# 只要 stdout 进 wc;grep 的错误信息仍可能在终端greppattern missing|wc-l

把 stderr 也并入管道:

greppattern missing2>&1|wc-l

Bash 还提供|&(同2>&1 |):

cmd|&other

读脚本:日志里「错误混进下游」时,看是否有2>&1


8. 多节管道与重定向

grepERROR app.log|sort|uniq-c|sort-nr

$?/PIPESTATUS每一节都有对应下标。

重定向作用在整个管道(常见写法):

grepERROR app.log|teereport.txt|wc-l# tee 同时写文件和 stdout,wc 统计行数
cmd1|cmd2>out.log2>&1# 只对整条管道末尾 cmd2 的 stdout/stderr 重定向规则见 S09-01# 更稳妥:{ cmd1 | cmd2; } >all.log 2>&1

复杂组合时,用{ ...; }分组(S09-03 子 shell 详讲)。


9. 读脚本时的常见模式

9.1 过滤 + 统计
awk'$3 > 500 {print}'access.log|wc-l
9.2 检查中间步骤(无 pipefail 时)
curl-fsS"$url"|jq.# 有 pipefail:curl 失败 → 管道失败# 无 pipefail:jq 解析空输入也可能 exit 0,危险
9.3| while read与退出码(两个问题)
n=0grep.f|whileread-rline;do((n++));doneecho"$n"# 子 shell:n 仍为 0(S07-02)grep.f|sort|whileread-rline;do...;done# sort 失败 + pipefail → 脚本可能退出;n 的问题仍要用 < f 解决
9.4 显式检查第一节
set-euopipefail{false;echogen;}|head-n1# 有 pipefail 时 false 导致管道失败

或不用 pipefail、手动查PIPESTATUS[0](脚本片段里少见)。


10. 对照表

问题默认pipefail
false | true$?01
grep 无匹配 | wc$?常为 0非 0
set -e是否因左端失败退出
查每一节PIPESTATUSPIPESTATUS

11. 注意点

说明
不要用$?猜第一节默认只有最后一节
PIPESTATUS及时保存下一条命令会清掉
SIGPIPE读者提前关闭,写者可能非 0
交互命令管道右端读终端时要小心(少见)
可移植pipefailPIPESTATUS为 Bash 等扩展;纯 sh 见 S13

读脚本检查清单

  • 脚本是否开了set -o pipefail(或等价)?
  • grep | ...左端失败是否会被掩盖?
  • 是否需要2>&1 |把错误也送进管道?
  • 是否误用| while read又在循环外用累加变量?
  • 检查每一节时是否用了PIPESTATUS而不是$?

练习

判断题

  1. A | B中,A 完全结束后 B 才开始。
  2. 默认情况下false | true$?为 0。
  3. 开启pipefail后,false | true$?为非 0。
  4. PIPESTATUS[0]表示管道第一个命令的退出码。
  5. 管道会把左边命令的 stderr 默认送进右边。
参考答案
  1. 错(并行;读者满或退出时写者可能 SIGPIPE)。
  2. 对。
  3. 对。
  4. 对。
  5. 错(默认只有 stdout)。

实操题

运行并写出$?${PIPESTATUS[*]}(Bash):

bash-c'false | true; echo exit=$?; echo pipe=${PIPESTATUS[*]}'bash-c'set -o pipefail; false | true; echo exit=$?; echo pipe=${PIPESTATUS[*]}'
参考答案

无 pipefail:exit=0pipe=1 0
有 pipefail:exit=1pipe=1 0

改错题

#!/usr/bin/env bashset-egrepERROR"$LOG"|mail-salert admin@example.comecho"alert sent"

grep无匹配时仍打印alert sent。如何改?

参考
set-euopipefailgrepERROR"$LOG"|mail-salert admin@example.comecho"alert sent"

或业务上允许无匹配:

ifgrepERROR"$LOG"|mail-salert admin@example.com;thenecho"alert sent"elseecho"no ERROR or mail failed">&2fi

下一篇预告

S09-03:《子 Shell 与命令替换:()$()》—$(cmd)`cmd`、子 shell( )与管道的区别。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/6 23:30:18

Linux内核动态修补与函数钩取:KernelPatch核心原理与实战指南

1. 项目概述&#xff1a;为什么我们需要KernelPatch&#xff1f;如果你和我一样&#xff0c;长期在Linux系统上折腾&#xff0c;无论是做安全研究、性能调优&#xff0c;还是驱动开发&#xff0c;迟早会遇到一个绕不开的坎&#xff1a;如何在不重新编译整个内核源码的情况下&am…

作者头像 李华
网站建设 2026/7/6 23:30:12

西安邮电大学期末考试秘籍:如何用历年真题实现高效备考

西安邮电大学期末考试秘籍&#xff1a;如何用历年真题实现高效备考 【免费下载链接】XUPT-Exam-Collection 西安邮电大学历年 期中/期末考试 卷子共享库 项目地址: https://gitcode.com/gh_mirrors/xu/XUPT-Exam-Collection 西安邮电大学期末考试试卷资源库是一个汇集了…

作者头像 李华
网站建设 2026/7/6 23:27:38

Unity 2021.1 手游FPS双摇杆控制:从PC到移动端的3步适配方案

Unity 2021手游FPS双摇杆控制&#xff1a;从PC到移动端的深度适配指南1. 移动端FPS控制的核心挑战当我们将PC端的FPS游戏移植到移动平台时&#xff0c;最根本的差异在于输入方式的彻底改变。PC玩家习惯的"WASD鼠标"这套黄金组合在触屏设备上需要被重新设计为虚拟双摇…

作者头像 李华
网站建设 2026/7/6 23:25:53

JPEXS Free Flash Decompiler:终极Flash反编译工具完整指南

JPEXS Free Flash Decompiler&#xff1a;终极Flash反编译工具完整指南 【免费下载链接】jpexs-decompiler JPEXS Free Flash Decompiler 项目地址: https://gitcode.com/gh_mirrors/jp/jpexs-decompiler 还在为Flash内容消失而烦恼吗&#xff1f;想要从那些经典SWF文件…

作者头像 李华
网站建设 2026/7/6 23:24:29

量子近似优化算法(QAOA)的工程化改进:Bang-bang控制策略解析与实践

1. 项目概述&#xff1a;当量子计算遇上“硬骨头”量子计算这玩意儿&#xff0c;听起来高大上&#xff0c;什么“量子霸权”、“指数级加速”&#xff0c;但真正干这行的人都知道&#xff0c;从实验室的演示芯片到解决实际商业问题&#xff0c;中间隔着十万八千里。其中一个最让…

作者头像 李华
网站建设 2026/7/6 23:17:33

ASM330LHH与STM32L4S5ZI的硬件协同设计与运动跟踪算法

1. 从传感器到系统&#xff1a;ASM330LHH与STM32L4S5ZI的硬件协同设计1.1 ASM330LHH的工业级性能解析这颗STMicroelectronics出品的6轴IMU芯片在运动跟踪领域堪称性能标杆。其核心优势在于将3轴加速度计和3轴陀螺仪集成在4x3x1mm的LGA封装内&#xff0c;却实现了4000dps的角速度…

作者头像 李华