为什么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
基本上,区别在于’eval’使用复合命令和仅执行复合命令.当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’d或ssh’d命令中的最后一个命令失败.
任何想法将不胜感激.
最佳答案 我还要提一下,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"