链式命令的退出状态

链式命令的退出状态

我想在变量中运行可能无效的命令cmd。我不能让它让我失败并检索退出状态。我可以尝试做的是将其通过管道传输:,然后我将获得成功的退出状态。

$ $cmd | :
$ echo $?
0

现在,我想知道cmd不单独运行它的退出状态。在 Bash 中,我可以使用PIPESTATUS.但我用的是破折号。

我尝试运行bash -c "$cmd | : ; rc=$(echo ${PIPESTATUS[@]} | head -c1)",但收到​​“错误替换错误”。

我的问题是:

  1. 如何实现返回破折号中第一个命令的退出状态的目标?
  2. 我正在做的事情是什么导致了破折号的错误?

答案1

如果您有完整的 shell 语法,那么您可以使用if,这不会对 shell 造成失败:

if (eval "$cmd"); then
    : # do nothing, it worked
else
    printf 'Command %s failed with code %d\n' "$cmd" $?
fi

请注意,您不能使用更明显的if ! eval…语法,因为否定将隐藏退出代码。之所以存在“不执行任何操作”,是因为 shell 语法需要一个包含命令的 then 块;您不能省略它或将其留空。

重要的是,if即使评估的命令失败,这也不是 shell 的失败。

括号中是在子 shell 中运行命令;这可以防止命令设置影响脚本的变量或执行诸如exit 1完全终止脚本之类的操作。

最后,请注意我如何使用eval而不是不加引号的$cmd.这是因为不带引号的命令会以您可能意想不到的方式进行分词。如果你有cmd='rm -Rf "foo * baz"',那么当你运行时,$cmd你实际运行的是rm -Rf \"foo * baz\"-将要将 展开*到目录中的所有文件,删除所有内容(除了两个文件"foobaz")。这是rm在全局扩展之前 的三个参数,而不是您所期望的。eval将应用正常的 shell 命令解析,我认为会减少意外情况。如果这是在脚本内构建的命令而不是从文本文件读取的行,则还有其他更安全的方法(例如使用数组)。

相关内容