脚本.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 -e
和 set -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/