bash – 为什么eval退出subshel​​l mid – \u0026\u0026 with set -e?

为什么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"
点赞