脚本.sh:
\n\nset -x\nset -e\nset -u\nset -o pipefail\n\nfoo=$(tail -1 <(false || { >&2 echo "failed" && exit 1; }) | echo "pipeline still running" || { >&2 echo "failed" && exit 1; }) || { >&2 echo "failed" && exit 1; }\n\necho "Script still running..."\nRun Code Online (Sandbox Code Playgroud)\n\n为什么echo "Script still running..."最终会被处决?set -e我认为和的组合set -o pipefail应该意味着false传播到主脚本并终止于,foo=...但 foo 被分配为“管道仍在运行”......并且当我希望脚本不会继续时,脚本会继续。我曾想过这个问题支持这个想法。
在阅读了有关 pipelinefail 的 bash 手册页(特别是)后,它指出A pipeline is a sequence of one or more commands separated by one of the control operators \xe2\x80\x98|\xe2\x80\x99 or \xe2\x80\x98|&\xe2\x80\x99.
那么我认为set不会传播到子 shell 中?有办法让这种情况发生吗?
作为参考,我正在使用
\n\n$ bash --version\nGNU bash, version 4.3.46(1)-release (x86_64-pc-linux-gnu)\nCopyright (C) 2013 Free Software Foundation, Inc.\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\nThis is free software; you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\nRun Code Online (Sandbox Code Playgroud)\n
与管道故障无关。
cat <(exit 1)
Run Code Online (Sandbox Code Playgroud)
...退出状态为 0,无论是否pipefail设置:进程替换不是管道组件,并且不检查其退出状态。
也就是说,在 bash 4.4 及更高版本中,您可以显式检查它,如下所示:
cat <(exit 1); pid=$!
wait "$pid" # this will have the exit status of the process substitution operation
Run Code Online (Sandbox Code Playgroud)
顺便说一句,这有令人信服的理由。考虑:
exec 3< <(echo hello; exit 1)
read greeting <&3
echo "Greeting is: $greeting"
Run Code Online (Sandbox Code Playgroud)
现在,您预计哪个命令会失败?它不可能是实际执行进程替换的重定向的地方,因为进程替换在执行该单个命令之后仍然保持活动状态,并且在read发生 a 之前,进程替换尚未失败。
它不会可靠read greeting,因为读取成功——只有在与该读取关联的写入完成之后exit,管道另一端的进程才会失败,并且不能保证在外部读取之前已经发生或没有发生这种情况。壳牌已进入决赛echo。