Bash Shell中的信號

2020-07-16 10:04:48
當沒有任何捕獲時,一個互動式 Bash Shell 會忽略 SIGTERM 和 SIGQUIT 信號。由 Bash 執行的非內部命令會使用 Shell 從其父進程繼承的信號處理程式。如果沒有啟用作業控制,非同步執行的命令會忽略除了有這些信號處理程式之外的 SIGINT 和 SIGQUIT 信號。由於命令替換而執行的命令會忽略鍵盤產生的作業控制信號SIGTTIN、SIGTTOU 和 SIGTSTP。

預設情況下,Shell 接收到 SIGHUP 信號後會退出。在退出之前,一個互動式的 Shell 會向所有的作業,不管是正在執行的還是已停止的,重新傳送 SIGHUP 信號。對已停止的作業,Shell 還會傳送 SIGCONT 信號以確保它能夠接收到 SIGHUP 信號。

若要阻止 Shell 向某個特定的作業傳送 SIGHUP 信號,可以使用內部命令 disown 將它從作業表中移除,或是用“disown -h”命令阻止 Shell 向特定的作業傳送 SIGHUP 信號,但並不會將特定的作業從作業表中移除。

我們通過如下範例,來了解一下 disown 命令的作用:
#將 sleep 命令放在後台執行,休眠30秒
[c.biancheng.net]$ sleep 30 &
[1] 8052

#列出當前 Shell 下所有作業的資訊
[c.biancheng.net]$ jobs -l
[1]+ 8052 Running    sleep 30 &

#將作業1從作業表中移除
[c.biancheng.net]$ disown %1

#再次列出當前 Shell 下所有作業的資訊
[c.biancheng.net]$ jobs -l

#查詢 sleep 進程
[c.biancheng.net]$ ps -ef | grep sleep
mozhiyan 8052 8092 cons1 11:28:21 /usr/bin/sleep

#列印當前 Shell 的進程號
[c.biancheng.net]$ echo $$
8092
在上述範例中,我們首先將命令“sleep 30”放在後台執行,此時,我們使用命令“jobs -l”可以看到作業表中有一個正在執行的作業,然後,我們使用命令“disown %1”將作業1從作業表中移除,再使用命令“jobs -l”會看到作業表中已經沒有了作業,但是我們發現其實“sleep 30”這個命令的進程仍然存在。此時,Shell 若接收到 SIGHUP 信號,它就不會向作業1重新傳送 SIGHUP 信號,此時如果我們退出 Shell,這個作業仍將繼續執行,而不會被終止。

我們再來看一下命令“disown -h”的用途:
#將 sleep 命令放在後台執行,休眠30秒
[c.biancheng.net]$ sleep 30 &
[1] 3184

#列出當前 Shell 下所有作業的資訊
[c.biancheng.net]$ jobs -l
[1]+ 3184 Running    sleep 30 &

#阻止 Shell 向作業1傳送 SIGHUP 信號
[c.biancheng.net]$ disown -h %1
[c.biancheng.net]$ jobs -l
[1]+ 3184 Running    sleep 30 &
我們看到,在執行了命令“disown -h %1”後,作業1並沒有從作業表中移除,但它己經被標記,所以即使 Shell 收到 SIGHUP 信號也不會向此作業傳送 SIGHUP 信號。因此, 如果此時我們退出 Shell,這個作業也仍將繼續執行,而不會被終止。

注意:如果使用內部命令 shopt 開啟了 Shell 的 huponexit 選項,當一個互動式的登入 Shell 退出時,會向所有的作業傳送 SIGHUP 信號。