我想在变量中运行可能无效的命令cmd
。我不能让它让我失败并检索退出状态。我可以尝试做的是将其通过管道传输:
,然后我将获得成功的退出状态。
$ $cmd | :
$ echo $?
0
现在,我想知道cmd
不单独运行它的退出状态。在 Bash 中,我可以使用PIPESTATUS
.但我用的是破折号。
我尝试运行bash -c "$cmd | : ; rc=$(echo ${PIPESTATUS[@]} | head -c1)"
,但收到“错误替换错误”。
我的问题是:
- 如何实现返回破折号中第一个命令的退出状态的目标?
- 我正在做的事情是什么导致了破折号的错误?
答案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\"
-将要将 展开*
到目录中的所有文件,删除所有内容(除了两个文件"foo
和baz"
)。这是rm
在全局扩展之前 的三个参数,而不是您所期望的。eval
将应用正常的 shell 命令解析,我认为会减少意外情况。如果这是在脚本内构建的命令而不是从文本文件读取的行,则还有其他更安全的方法(例如使用数组)。