Bash

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

  • October 4, 2018

我知道在 shell 腳本中,“退出”通常意味著自願或至少成功終止會話(或會話中的程序),並且有幾種不同的退出模式;以下是我知道的:

1.一個簡單的exit命令

如果我在第一個 shell 會話(shell 會話 0)中,它通常會導致 shell CLI視窗關閉,但如果我在某個子會話(如 shell 會話 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

3.一個未添加的腳本退出

如果我沒記錯的話,當 Bash 腳本結束執行時,它的“結束”實際上是常用 nix 術語中的“退出”——腳本本身是使用者退出回 CLI 會話​​的會話。這裡也可能給出一些退出程式碼。*

我的問題

通常在 shell 腳本中,特別是在 Bash 中是否還有其他“退出模式”?

“退出”通常意味著自願或至少成功終止

至少 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 hits 。(*)

從技術上講,在案例1到6中,執行腳本的shell程序自願退出(即程序呼叫exit())。另一方面,從腳本set -e本身的角度來看,由於set -u或語法錯誤而終止很可能被稱為非自願。但是 shell 腳本與 shell 解釋器不同。

在 1 到 3 中,習慣是使用退出狀態為零表示成功完成,使用非零值表示失敗。非零值的確切含義取決於實用程序。有些可能只使用零和一,有些可能針對不同的情況使用不同的非零狀態。例如,grep用於1表示未找到匹配項,大於1表示錯誤的值。Bash 的內置函式也用於2指示無效選項等錯誤。使用類似的自定義可能很有用,但您需要記錄腳本的退出狀態的含義。請注意,退出狀態通常限制為 8 位,因此範圍為 from0255

在 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。)

引用自:https://unix.stackexchange.com/questions/472098