如何在 bash 中抑制 SIGPIPE?

car*_*mer 5 bash pipe

我正在尝试执行以下代码:

set -euxo pipefail
yes phrase | make installer
Run Code Online (Sandbox Code Playgroud)

在哪里Makefile使用phrasefrom stdin 创建安装程序文件。但是,此命令以错误代码 141 结尾,这会破坏我的 CI 构建。这个例子可以简化为:

yes | tee >(echo yo)
Run Code Online (Sandbox Code Playgroud)

从这里看到的内容:管道故障 (141) 当管道输出到三通时——为什么?- 这个错误意味着管道消费者刚刚停止消费输出 - 这在我的情况下非常好。

有没有办法抑制管道错误,然后从make installer?

Ste*_*itt 7

141 退出代码表示进程失败,并显示SIGPIPE; 这发生yes在管道关闭时。要为您的 CI 掩盖这一点,您需要使用类似的东西来掩盖错误

(yes phrase ||:) | make installer
Run Code Online (Sandbox Code Playgroud)

这将运行yes phrase,如果失败,运行:以代码 0 退出。这足够安全,因为yes除了无法写入之外没有太多原因导致失败。

要调试此类管道问题,最好的方法是查看PIPESTATUS

yes phrase | make installer || echo ${PIPESTATUS[@]}
Run Code Online (Sandbox Code Playgroud)

这将显示失败时管道所有部分的退出代码。然后可以适当处理那些因退出代码 141 而失败的问题。特定错误代码的通用处理模式是

(command; ec=$?; if [ "$ec" -eq 141 ]; then exit 0; else exit "$ec"; fi)
Run Code Online (Sandbox Code Playgroud)

(感谢Hauke Laging);这会运行command,如果command成功则以代码 0 退出,或者以代码 141 退出。其他退出代码按原样反映。

  • 对于偏执狂:`( yes; ec=$?; if [ "$ec" -eq 141 ]; then exit 0; else exit "$ec"; fi ) | 制作安装程序`;-) (3认同)
  • 如果“make”停止读取,则会导致“yes”失败,并显示“SIGPIPE”,而不是“make”。如果“make”无法“写入”管道,则“make”将失败并显示“SIGPIPE”。 (2认同)
  • 或者 `(cmd; exit "$(( $? == 141 ? 0 : $? ))")` (2认同)
  • 另请参阅 `[ "$(kill -l "$?")" = PIPE ]` 以避免硬编码该 141。 (2认同)