linux - 在进程替换中的命令失败后,bash pipefail 仍在运行 w/set -e

标签 linux bash

脚本.sh:

set -x
set -e
set -u
set -o pipefail

foo=$(tail -1 <(false || { >&2 echo "failed" && exit 1; }) | echo "pipeline still running" || { >&2 echo "failed" && exit 1; }) || { >&2 echo "failed" && exit 1; }

echo "Script still running..."

为什么 echo "Script still running..." 最终被执行了?我认为 set -eset -o pipefail 的组合应该意味着 false 传播到主脚本并终止于 foo=... 但 foo 被分配为“管道仍在运行”...并且脚本在我希望它不会继续运行时继续。我以为this question支持这个想法。

在阅读关于 pipefail 的 bash 手册页(特别是)后,它声明 管道是由控制运算符“|”或“|&”之一分隔的一个或多个命令的序列。

那么,我认为 set 不会传播到子 shell 中?有没有办法让这种情况发生?

作为引用,我正在使用

$ bash --version
GNU bash, version 4.3.46(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

最佳答案

与管道失败无关。

cat <(exit 1)

...退出状态为 0,设置或不设置 pipefail:进程替换不是管道组件,不会检查它们的退出状态。

也就是说,在 bash 4.4 及更高版本中,您可以按如下方式明确检查它:

cat <(exit 1); pid=$!
wait "$pid" # this will have the exit status of the process substitution operation

顺便说一句,这有令人信服的理由。考虑:

exec 3< <(echo hello; exit 1)
read greeting <&3
echo "Greeting is: $greeting"

现在,您希望哪个命令失败?它不可能是实际执行进程替换重定向的那个,因为进程替换在该单个命令执行之后仍然处于事件状态,并且在发生 read 之前,进程替换 还没有失败

它不会可靠地是read greeting,因为读取成功——只有与该读取关联的写入完成后管道另一端的进程失败,并且不能保证 exit 在外壳进入最终 echo 之前发生或没有发生。

关于linux - 在进程替换中的命令失败后,bash pipefail 仍在运行 w/set -e,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42703281/

相关文章:

linux - 在 AWS Code Commit 中使用用户名和密码进行 Git pull/克隆

bash - 当使用 '-print' 时,从 'find' 命令中遗漏 '-prune'

linux - Bash - 检查字符串是否以预定义字符串(子字符串)开头

bash - 从终端输出中删除发送命令,同时保留所需的输出

linux - 压缩和删除 unix 中的日志

c - Linux 上 fifos 的奇怪行为

linux - Centos cgconfig 启动失败

linux - 两次 Bash 命令替换

bash - 以编程方式检测已安装的 Common Lisp 实现

PowerShell 的 Write-Host 的 Bash 等效项(写入终端但不通过管道传输到标准输出)