为什么 eval 使用 set -e 退出 subshell mid-&&?
Why does eval exit subshell mid-&& 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 命令就不会错误地退出我的 subshell,因为这正如我所期望的那样工作:
$ 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=""
local remote=""
if [ ! -z "$remote" ]; then
$SSH $remote "$command" || :
else
eval "$command" || :
fi
}
我在脚本中使用 set -e
。这个函数中的 ssh 也会出现同样的问题——如果 ssh 脚本中的最后一个命令是一个提前终止的复合命令,则整个命令会因错误而终止。我希望这样的命令表现得好像它们在本地执行一样 - 提前终止复合命令不应导致 ssh 或 eval 到 return 1,从而使整个命令失败。如果我在我的 eval 语句或我的 ssh 语句的末尾附加 || :
,那么所有这些命令都会成功,即使它们不应该因为 eval'd 或 ssh'd 命令中的最后一个命令失败。
如有任何想法,我们将不胜感激。
eval
算作自己的命令,有自己的退出代码。
由于 eval "false && true"
returns 退出代码为 1,因此触发 set -e
。
我还应该提到 set -e
非常容易出错;请参阅 http://mywiki.wooledge.org/BashFAQ/105 以获取大量示例。因此,最佳 解决方案可能是放弃它,并编写自己的逻辑来检测错误并中止。
那不碍事。 . .
这里的问题是 eval "false && true"
是单个命令,计算结果为 false(非零),因此 set -e
在该命令 运行s 后中止。
如果您改为 运行 eval "false && true; true"
,您将不会看到此行为,因为 eval
的计算结果为真(零)。 (请注意,尽管 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"
为什么 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 命令就不会错误地退出我的 subshell,因为这正如我所期望的那样工作:
$ 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=""
local remote=""
if [ ! -z "$remote" ]; then
$SSH $remote "$command" || :
else
eval "$command" || :
fi
}
我在脚本中使用 set -e
。这个函数中的 ssh 也会出现同样的问题——如果 ssh 脚本中的最后一个命令是一个提前终止的复合命令,则整个命令会因错误而终止。我希望这样的命令表现得好像它们在本地执行一样 - 提前终止复合命令不应导致 ssh 或 eval 到 return 1,从而使整个命令失败。如果我在我的 eval 语句或我的 ssh 语句的末尾附加 || :
,那么所有这些命令都会成功,即使它们不应该因为 eval'd 或 ssh'd 命令中的最后一个命令失败。
如有任何想法,我们将不胜感激。
eval
算作自己的命令,有自己的退出代码。
由于 eval "false && true"
returns 退出代码为 1,因此触发 set -e
。
我还应该提到 set -e
非常容易出错;请参阅 http://mywiki.wooledge.org/BashFAQ/105 以获取大量示例。因此,最佳 解决方案可能是放弃它,并编写自己的逻辑来检测错误并中止。
那不碍事。 . .
这里的问题是 eval "false && true"
是单个命令,计算结果为 false(非零),因此 set -e
在该命令 运行s 后中止。
如果您改为 运行 eval "false && true; true"
,您将不会看到此行为,因为 eval
的计算结果为真(零)。 (请注意,尽管 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"