可以看到很多 shell
脚本在开头第一行都写着 #!/bin/sh -e
,那么这里的 '-e'
是什么意思呢?简单来说,使用 '-e'
后,shell
脚本在执行过程中,若遇到某条命令返回非零状态,则会立即退出,并且上述用法等同于 set -e
语句,在 GNU Bash 的官方文档中对 '-e'
有一个明确的解释:
-e
Exit immediately if a pipeline (see Pipelines), which may consist of a single simple command (see Simple Commands), a list (see Lists of Commands), or a compound command (see Compound Commands) returns a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command’s return status is being inverted with !. If a compound command other than a subshell returns a non-zero status because a command failed while -e was being ignored, the shell does not exit. A trap on ERR, if set, is executed before the shell exits.
This option applies to the shell environment and each subshell environment separately (see Command Execution Environment), and may cause subshells to exit before executing all the commands in the subshell.
If a compound command or shell function executes in a context where -e is being ignored, none of the commands executed within the compound command or function body will be affected by the -e setting, even if -e is set and a command returns a failure status. If a compound command or shell function sets -e while executing in a context where -e is ignored, that setting will not have any effect until the compound command or the command containing the function call completes.
上述内容所讲的使用规则及场景比较复杂,在实际使用时,若不确定某种用法是否符合预期,则应提前测试。下面展示几种常规用法:
1、函数调用返回非零状态
test.sh
代码:
#!/bin/sh -e
foo() {
echo "foo()"
return 1
}
foo
echo "test.sh done!"
test.sh
运行结果:
$ ./test.sh
foo()
2、子 shell
以非零状态退出
sub.sh
代码:
#!/bin/sh
echo "sub.sh done"
exit 1
test.sh
代码:
#!/bin/sh -e
./sub.sh
echo "test.sh done"
test.sh
运行结果:
$ ./test.sh
sub.sh done
3、子 shell
中的函数调用返回非零状态
sub.sh
代码:
#!/bin/sh
foo_in_sub() {
echo "foo_in_sub()"
return 1
}
foo_in_sub
echo "sub.sh done"
test.sh
代码:
#!/bin/sh -e
./sub.sh
echo "test.sh done"
test.sh
运行结果:
$ ./test.sh
foo_in_sub()
sub.sh done
test.sh done
可以看到,当子 shell
中的函数调用返回非零状态时,子 shell
并不会立即退出,父 shell
也不会立即退出。但如果是通过 source ./sub.sh
的方式在父 shell
中直接调用子 shell
里面的函数,那么当出现函数返回非零状态时父 shell
会立即退出(在更复杂的使用场景下,可能不是这样,需要大家确认)。
4、使能 '-e'
后,如何进行错误处理?
有时候虽然我们使能了 '-e'
,但还是希望能够感知错误的发生,以及对错误进行处理,而不是直接退出。此时我们可以使用 "||"
表达式来进行错误处理,如下所示:
sub.sh
代码:
#!/bin/sh
echo "sub.sh done"
exit 1
test.sh
代码:
#!/bin/sh -e
failed=false
./sub.sh || failed=true
if $failed ; then
echo "sub.sh exec failed"
fi
echo "test.sh done"
test.sh
运行结果:
$ ./test.sh
sub.sh done
sub.sh exec failed
test.sh done
5、与 set -e
相反,使用 set +e
可以关掉上述功能,示例略。