通常在 shell 腳本中,特別是在 Bash 中存在哪些退出模式?
我知道在 shell 腳本中,“退出”通常意味著自願或至少成功終止會話(或會話中的程序),並且有幾種不同的退出模式;以下是我知道的:
1.一個簡單的
exit
命令如果我在第一個 shell 會話(shell 會話 0)中,它通常會導致 shell CLI視窗關閉,但如果我在某個子會話(如 shell 會話 1 或更高版本)中,執行通常只會將我的使用者移回上一個會話(例如
1 → 0
)。2.
exit SOME_EXIT-CODE
命令我發現在這種退出中使用了三個主要的退出程式碼:
exit 0
(成功)。exit 1
(一般錯誤如“除以零”和其他不允許的操作)。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 腳本可能會退出終止,至少由於以下原因:
- 腳本執行到腳本結束。腳本的退出狀態是最後執行的命令的退出狀態。
- 該腳本執行不帶參數的
exit
內置命令。同樣,退出狀態是最後執行的命令的狀態。- 該腳本執行
exit
帶有參數的命令。退出狀態是參數的值。- 該腳本在
set -u
/set -o nounset
生效時引用了一個未設置的變數。退出狀態取決於 shell,但不為零。(Bash 似乎使用127
.)(*)- 該腳本執行的命令在
set -e
/set -o errexit
生效時失敗。退出狀態是失敗命令的狀態。(但有關 .的問題,請參閱BashFAQ 105。set -e
)- 腳本遇到語法錯誤。shell 的退出狀態是非零的。(Bash 似乎使用
1
.)(*)- 腳本接收到一個信號,導致它終止。並非所有信號都會導致終止,信號可以被忽略,也可以使用
trap
內置命令在腳本中設置處理程序。Ctrl-C
這也適用於發送SIGINT
信號的 eq hits 。(*)從技術上講,在案例1到6中,執行腳本的shell程序自願退出(即程序呼叫
exit()
)。另一方面,從腳本set -e
本身的角度來看,由於set -u
或語法錯誤而終止很可能被稱為非自願。但是 shell 腳本與 shell 解釋器不同。在 1 到 3 中,習慣是使用退出狀態為零表示成功完成,使用非零值表示失敗。非零值的確切含義取決於實用程序。有些可能只使用零和一,有些可能針對不同的情況使用不同的非零狀態。例如,
grep
用於1
表示未找到匹配項,大於1
表示錯誤的值。Bash 的內置函式也用於2
指示無效選項等錯誤。使用類似的自定義可能很有用,但您需要記錄腳本的退出狀態的含義。請注意,退出狀態通常限制為 8 位,因此範圍為 from0
到255
。在 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
。)