Shell

當終端模擬器退出時,為什麼shell也會退出?

  • February 22, 2022

當我啟動終端仿真器(例如 qterminal)時,它會啟動預設 shell(例如 bash)。當我退出終端時(例如,通過點擊 x 按鈕或通過終止終端),shell 也會退出。沒有剩下shell的程序。我想知道這個機制是如何實現的。

起初,我懷疑終端向外殼發送了一些信號。所以我在 shell 中擷取了 SIGQUIT、SIGINT、SIGTERM、SIGHUP,但沒有擷取任何信號。除了信號,我不知道。

它可能依賴於終端和外殼,也可能依賴於作業系統。請告訴我有關這種情況的任何資訊。

通常終端會向程序發送掛斷(SIGHUP)。此外,當終端關閉 pty 的“主”端時,附加到它的某些程序也會自動接收來自核心的 SIGHUP——無論終端是否發送了 SIGHUP。

雖然來自核心的信號並沒有發送到所有以 pty 作為控制終端的程序——我沒有準確檢查,但我認為它是專門發送到“前台 pgroup”的,與 SIGINT/ 基本相同來自 Ctrl+C/Ctrl+\ 的 SIGQUIT。

Shell 本身(例如 Bash)已經有一個 SIGHUP 處理程序,它為 shell 管理的所有後台作業提供額外的 SIGHUP (忽略那些已disown編輯的作業),例如sleep 1h &,當 Bash 即將退出時,a 將被 SIGHUP自己收到 SIGHUP。

例如,乾淨地關閉終端時:

$ sudo strace -p ${pid_of_bash}
strace: Process 102874 attached
pselect6(1, [0], NULL, NULL, NULL, {sigmask=[], sigsetsize=8}) = ? ERESTARTNOHAND
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=87390, si_uid=1000} ---
--- SIGCONT {si_signo=SIGCONT, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]})                 = -1 EINTR (Interrupted system call)
--- SIGHUP {si_signo=SIGHUP, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]})                 = -1 EINTR (Interrupted system call)
[...]

當使用調試器close(ptmx_fd)從終端程序發出時:

$ sudo strace -p ${pid_of_bash}
pselect6(1, [0], NULL, NULL, NULL, {sigmask=[], sigsetsize=8}) = 1 (in [0])
--- SIGHUP {si_signo=SIGHUP, si_code=SI_KERNEL} ---
--- SIGCONT {si_signo=SIGCONT, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]})                 = 1
read(0, "", 1)                          = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
ioctl(2, TCXONC, TCOON)                 = -1 EIO (Input/output error)
write(2, "\33[?2004l\r", 9)             = -1 EIO (Input/output error)

最後,當 pty 關閉時,shell(或其他前台程序)將在嘗試從中讀取時收到 EOF(即read()返回 0),它會像按下 Ctrl+D 一樣處理 - 這通常也會導致程序退出,儘管它當然可以忽略 EOF(在這種情況下,我看到一個特定的程序進入無限循環,當它決定忽略 SIGHUPEOF 時)。

在到達您的自定義 SIGHUP 處理程序之前,shell 很有可能在 EOF 上退出。例如,我可以在 GNOME 終端下的 Bash 中重現您的結果(trap ... SIGHUP沒有被呼叫),*但是,*如果我另外設置IGNOREEOF=1告訴 Bash 不要在 EOF 上退出,那麼確實會呼叫自定義 SIGHUP 陷阱。

一個自定義陷阱也恰好覆蓋了Bash 的預設“退出 SIGHUP”行為。因此,當我告訴 Bash 忽略 EOF擷取 SIGHUP 時,它實際上一直在嘗試向不存在的 tty 列印提示 - ‘strace’ 輸出顯示它呼叫了我所有常用的 PROMPT_COMMAND 掛鉤,試圖將提示寫入標準輸出,獲得 EIO ,然後嘗試將錯誤消息寫入stderr,從中獲取EIO *,*然後才確定足夠多並退出。

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