请考虑这两个脚本:
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
是:
[...]如果没有条件测试为真则为零。
(来源)