通常在 shell 脚本中存在哪些退出模式,特别是在 Bash 中?

2 bash shell-script function exit exit-status

我知道在 shell 脚本中,“退出”通常意味着自愿或至少成功终止会话(会话中的进程),并且有几种不同的退出模式;以下是我所知道的:

1.一个简单的exit命令

如果我在第一个 shell 会话(shell-session 0)中,它通常会导致 shell CLI窗口关闭,但如果我在某个子会话(如 shell-session 1 或更高版本)中,执行通常只会将我的用户移回上一个会话(例如1 ? 0)。

2.exit SOME_EXIT-CODE命令

我发现在这种退出中使用的三个主要退出代码

  1. exit 0 (成功)。
  2. exit 1 (一般错误,例如“除以零”和其他不允许的操作)。
  3. exit 2(如在 Bash 4.xx 中 - 滥用 shell 内置函数,一个例子是空函数;myFunc() {})。

我经常发现这些添加到命令序列的末尾作为其执行结果指标;有时作为单元测试的一部分,例如:

domain="$1" && test -z "$domain" && exit 2 
# Test if a user passes only one domain as a parameter, when executing this script
Run Code Online (Sandbox Code Playgroud)

3.一个非添加的脚本退出

如果我没记错的话,当 Bash 脚本结束运行时,它的“结束”实际上是常见的 *nix 术语中的“退出”——脚本本身是一个会话,用户从中退出回到 CLI 会话。这里也可能给出一些退出代码

我的问题

通常在 shell 脚本中,尤其是在 Bash 中,是否还有其他“退出模式”?

ilk*_*chu 6

“退出”通常意味着自愿或至少成功终止

至少 POSIX 文本似乎仅将exit用于进程的自愿终止,而不是因外部原因而被终止。(参见例如wait())被信号杀死的进程几乎不算成功,因此任何成功的终止在这个意义上都必须是“退出”。尽管我希望这些术语在非正式使用中的使用不那么严格。

通常在 shell 脚本中,尤其是在 Bash 中,是否还有其他“退出模式”?

模式在某些上下文中具有特定的技术含义(例如chmod()),但我在这里想不出一个含义,所以我不确定您要问的是什么。

在任何情况下,至少由于以下原因,shell 脚本可能会退出终止:

  1. 脚本运行到脚本结束。脚本的退出状态是执行的最后一个命令的退出状态。
  2. 该脚本运行不带参数的exit内置命令。同样,退出状态是执行的最后一个命令的状态。
  3. 该脚本运行exit带有参数的命令。退出状态是参数的值。
  4. set -u/set -o nounset生效时,脚本引用了一个未设置的变量。退出状态取决于 shell,但不为零。(Bash 似乎使用127.) (*)
  5. 该脚本运行的命令在set -e/set -o errexit生效时失败。退出状态是失败命令的退出状态。(但有关. 的问题,请参阅BashFAQ 105。set -e
  6. 该脚本遇到语法错误。shell 的退出状态为非零。(Bash 似乎使用1.) (*)
  7. 脚本收到一个信号,导致它终止。并非所有信号都会导致终止,信号可以被忽略,也可以使用trap内置命令在脚本中设置处理程序。这也适用于Ctrl-C发送SIGINT信号的eq hit 。(*)

从技术意义上讲,在情况 1 到 6 中,运行脚本的shell 进程自愿退出(即进程调用exit())。在另一方面,从该点脚本本身,终止因set -eset -u或语法错误很可能被称为是非自愿的。但是shell脚本与shell解释器不同。

在 1 到 3 中,习惯是使用零退出状态表示成功完成,使用非零值表示失败。非零值的确切含义取决于效用。有些可能仅使用零和一,有些可能针对不同情况使用不同的非零状态。例如,grepuses1表示未找到匹配项,而值大于则1表示错误。Bash 的内置函数还用于2指示无效选项等错误。使用类似的自定义可能很有用,但您需要记录脚本的退出状态意味着什么。请注意,退出状态通常限制为 8 位,因此范围是从0255

在 4 到 6 中,情况通常被认为是某种失败,因此退出状态为非零。7、没有退出状态。相反,当进程因信号而终止时,wait()系统调用会指示相关信号。如果父进程是一个shell,它通常用一个退出状态来表示它128 + <signal number>,例如,143对于一个以 终止的子进程SIGTERM

(* 与脚本不同,交互式 shell 不会因语法错误或set -u或而退出SIGINT。)

如果我在第一个 shell 会话中,它通常会导致 shell CLI 窗口关闭

如果它启动的进程退出,终端模拟器通常会关闭。但这取决于终端模拟器,而不是外壳的功能。终端仿真器可能会决定保持窗口打开以告诉用户他们的程序已终止,并且您也可以在终端仿真器中运行除 shell 之外的其他程序。

如果我在某个子会话中,执行通常只会将我的用户移回上一个会话。

如果您使用交互式 shell 启动另一个 shell,则父 shell 会在子 shell 终止时继续。但同样,这与 shell 无关,如果您启动编辑器或仅从交互式 shell 运行任何命令,也会发生同样的情况。当子进程终止时,父 shell 继续接受来自用户的命令。

Bash 确实保留了一个变量SHLVL,每次 Bash 启动时都会增加一个,因此从某种意义上说,它确实具有嵌套 shell 的内部概念。但我不认为“子会话”这个词很常见,更不用说任何类型的编号了。(我认为SHLVL初始化在1.)