为单个管道命令设置 pipefail

为单个管道命令设置 pipefail

我需要从非 BASH 脚本(即 PHP 脚本)执行许多管道 shell 命令,如下所示:

command1 | command2 | command3

因此,如果command1失败并返回非零退出代码,则其他每个命令也会失败。到目前为止,我想到的是:

set -o pipefail && command1 | command2 | command3

但即使它可以从终端正常运行,但如果从脚本执行,它会产生以下结果:

sh: 1: 设置:非法选项 -o pipefail

答案1

从 Bash 命令行,你需要调用子 shell 以避免pipefail随后被设置:

$ (set -o pipefail && command1 | command2 | command3)

这会将该选项的效果限制pipefail在由括号创建的子 shell 内(...)

一个真实的例子:

$ (set -o pipefail && false | true) && echo pipefail inactive || echo pipefail active
pipefail active

如果你使用带有选项的显式 shell 调用,则-c不需要子 shell,无论是带有bash还是带有sh别名bash

$ bash -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active
$ sh -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active

由于您sh不接受该pipefail选项,我不得不假设它要么是某个旧版本或修改版本bash- 或者它实际上完全是其他 shell。

答案2

不确定为什么上面没有提到,但可以pipefail使用明确取消设置set +o pipefail

set -o pipefail
command1 | command2 | command3
set +o pipefail

如果你正在执行一个片段,并且不确定是否pipefail已经设置,你可以按照前面的建议将它与子 shell 一起使用:

# explicitly execute with pipefail set
(set -o pipefail ; command1 | command2 | command3 )
# explicitly execute with pipefail unset
(set +o pipefail ; command1 | command2 | command3 )

答案3

您可以将 $(command1) 与 $? 结合使用:

a=$(echo "a")
[ $? -eq 0 ] && b=$(echo $a"b")
[ $? -eq 0 ] && c=$(echo $b"c")
echo $c

打印“abc”

a=$(ls unexitingDir)
[ $? -eq 0 ] && b=$(echo $a"b")
[ $? -eq 0 ] && c=$(echo $b"c")
echo $c

印刷 ””。

“[ $? -eq 0 ] &&” 表示只有前一个命令成功执行,才会执行后面的命令。

这虽然没有回答您的问题,但却可以解决您的问题。

相关内容