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

时间:2017-03-09 18:53:18

标签: linux bash

script.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手册页后,它指出A pipeline is a sequence of one or more commands separated by one of the control operators ‘|’ or ‘|&’.

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

供参考,我正在使用

$ 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.

1 个答案:

答案 0 :(得分:2)

与pipefail没什么关系。

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已经发生过或没有发生过。{/ p>