为什么bash在子shell中使用复合命令执行我期望的事情:
$ bash -x -c 'set -e; (false && true; echo hi); echo here'
+ set -e
+ false
+ echo hi
hi
+ echo here
here
但不要做我期望的事情:
$ bash -x -c 'set -e; (eval "false && true"; echo hi); echo here'
+ set -e
+ eval 'false && true'
++ false
基本上,区别在于“复合命令”和“执行复合命令”之间的区别。当shell执行复合命令时,复合命令中失败的非终端命令不会导致整个复合命令失败,它们只是终止命令。但是当eval运行复合命令并且任何非终端子命令以错误终止命令时,eval会终止命令并显示错误。
我想我需要像这样格式化我的eval语句:
eval "false && true" || :
这样eval命令就不会因为错误而退出我的子shell,因为这可以解决这个问题:
$ bash -x -c 'set -e; (eval "false && true" || :; echo hi); echo here'
+ set -e
+ false
+ echo hi
hi
+ echo here
here
我遇到的问题是我写了一个函数:
function execute() {
local command="$1"
local remote="$2"
if [ ! -z "$remote" ]; then
$SSH $remote "$command" || :
else
eval "$command" || :
fi
}
我在我的脚本中使用set -e
。此函数中的ssh也会出现同样的问题 - 如果ssh脚本中的最后一个命令是一个提前终止的复合命令,则整个命令将以错误终止。我希望这样的命令行为好像它们在本地执行一样 - 早期终止复合命令不应该导致ssh或eval返回1,导致整个命令失败。如果我在我的eval语句或ssh语句的末尾添加|| :
,那么所有这些命令都会成功,即使它们不应该是因为eval中的最后一个命令或ssh&#39 ; d命令失败。
非常感谢任何想法。
答案 0 :(得分:2)
我还应该提到set -e
非常容易出错;有关一些示例,请参阅http://mywiki.wooledge.org/BashFAQ/105。因此,最佳解决方案可能是免除它,并编写自己的逻辑来检测错误并中止。
那个偏僻。 。
这里的问题是eval "false && true"
是单个命令,并且计算结果为false(非零),因此set -e
在该命令运行后中止。
如果您要运行eval "false && true; true"
,则不会看到此行为,因为eval
计算结果为true(零)。 (请注意,虽然eval
确实实现了set -e
行为,但它遵循false && true
不会中止的规则。)
顺便说一下,这并不是eval
特有的。由于同样的原因,子shell会给出相同的结果:
$ bash -x -c 'set -e; (false && true); echo here'
+ set -e
+ false
对于您的问题,最简单的解决方法可能只是在达到目的时运行额外的true
:
$SSH $remote "set -e; $command; true"
eval "$command; true"
答案 1 :(得分:0)
eval
将自己的命令视为自己的退出代码。
由于eval "false && true"
返回退出代码1,因此会触发set -e
。