为什么 [] test 使这个脚本失败?

为什么 [] test 使这个脚本失败?

请考虑这两个脚本:

run.sh:

#!/bin/bash
set -euo pipefail
. "$(dirname $(realpath $BASH_SOURCE))"/init-sudo-script.sh

init-sudo-script.sh

[ ${#BASH_SOURCE[@]} -eq 1 ]\
    && echo "must be sourced by another script."\
    && exit 10

[ $EUID -ne 0 ]\
    && echo "must be executed as root."\
    && exit 20

这是正确的,这也是我期望发生的事情:

$ ./run.sh
must be executed as root.
$ echo $?
20

但这我无法理解:

$ sudo ./run.sh
$ echo $?
1

我知道问题是[ $EUID -ne 0 ]因为当我删除脚本时它会起作用。

我还了解set -e使脚本在出现任何错误时退出。

我不明白的是为什么第一个保护条件 ( [ ${#BASH_SOURCE[@]} -eq 1 ]) 在失败时不会以 1 退出,但第二个却会退出。

有人明白这里发生了什么吗?

===更新===

我找到了一种让它按我的预期工作的方法:

if [ $EUID -ne 0 ]; then
    echo "must be executed as root."\
    && exit 20
fi

我会把它抛在脑后,但我正在投资让 Bash 变得更好。因此,如果有人能澄清发生了什么,我将很高兴听到。

答案1

我还了解set -e使脚本在出现任何错误时退出。

不是“出现任何错误”。也有例外,其中之一是:

如果失败的命令是在 或&&列表中执行的任何命令的 [...] 一部分,除了最后的或, [...]||后面的命令之外, shell 不会退出&&||

(来源

如果[ ${#BASH_SOURCE[@]} -eq 1 ]失败,则 shell 将不会退出,因为set -e.

同样,如果[ $EUID -ne 0 ]失败,则 shell 将不会退出,因为set -e.但它会在之后退出因为剧本结束了,即因为没有什么要执行的了。然后脚本的退出状态将是最后执行的命令的退出状态;而它恰好是失败的[。这就是为什么你会得到1.

将(始终成功的无操作命令)放在:测试的末尾init-sudo-script.sh并重新运行测试。sudo ./run.sh将返回,0因为最后一个命令将是:.


您更新的代码if不同,因为退出状态if是:

[...]如果没有条件测试为真则为零。

(来源

相关内容