訊號是一種處理序間通訊機制,它給應用程式提供一種非同步軟體中斷,使應用程式有機會接受其他程式活終端發送的命令(即訊號)。應用程式收到訊號後,有三種處理方式:忽略,預設,或捕捉。進程收到一個訊號後,會檢查對該訊號的處理機制。如果是SIG_IGN,就忽略該訊號;如果是SIG_DFT,則會採用系統預設的處理動作,通常是終止進程或忽略該訊號;如果給該訊號指定了一個處理函數(捕捉),則會中斷當前進程正在執行的任務,轉而去執行該訊號的處理函數,返回後再繼續執行被中斷的任務。
在有些情況下,我們不希望自己的shell指令碼在運行時刻被中斷,比如說我們寫得shell指令碼設為某一使用者的預設shell,使這一使用者進入系統後只能作某一項工作,如Database Backup, 我們可不希望使用者使用Ctrl c之類便進入到shell狀態,做我們不希望做的事情。這便用到了訊號處理。
以下是一些你可能會遇到的,要在程式中使用的更常見的訊號:
訊號名稱 |
訊號數 |
描述 |
SIGHUP |
1 |
本訊號在使用者終端串連(正常或非正常)結束時發出, 通常是在終端的控制進程結束時, 通知同一session內的各個作業, 這時它們與控制終端不再關聯。 登入Linux時,系統會分配給登入使用者一個終端(Session)。在這個終端啟動並執行所有程式,包括前台進程組和後台進程組,一般都屬於這個Session。當使用者退出 Linux登入時,前台進程組和後台有對終端輸出的進程將會收到SIGHUP訊號。這個訊號的預設操作為終止進程,因此前台進程組和後台有終端輸出的進程就會中止。對於與終端脫離關係的守護進程,這個訊號用於通知它重新讀取設定檔。 |
SIGINT |
2 |
程式終止(interrupt)訊號, 在使用者鍵入INTR字元(通常是Ctrl C)時發出。 |
SIGQUIT |
3 |
和SIGINT類似, 但由QUIT字元(通常是Ctrl /)來控制. 進程在因收到SIGQUIT退出時會產生core檔案, 在這個意義上類似於一個程式錯誤訊號。 |
SIGFPE |
8 |
在發生致命的算術運算錯誤時發出. 不僅包括浮點運算錯誤, 還包括溢出及除數為0等其它所有的算術的錯誤。 |
SIGKILL |
9 |
用來立即結束程式的運行. 本訊號不能被阻塞, 處理和忽略。 |
SIGALRM |
14 |
時鐘定時訊號, 計算的是實際的時間或時鐘時間. alarm函數使用該訊號。 |
SIGTERM |
15 |
程式結束(terminate)訊號, 與SIGKILL不同的是該訊號可以被阻塞和處理. 通常用來要求程式自己正常退出. shell命令kill預設產生這個訊號。 |
捕獲訊號
當你按下Ctrl + C鍵或Break鍵在終端一個shell程式的執行過程中,正常程式將立即終止,並返回命令提示字元。這可能並不總是可取的。例如,你可能最終留下了一堆臨時檔案,將不會清理。
捕獲這些訊號是很容易的,trap命令的文法如下:
$ trap commands signals
這裡的命令可以是任何有效Linux命令,或一個使用者定義的函數,訊號可以是任意數量的訊號,你想來捕獲的列表。
在shell指令碼中的陷阱有三種常見的用途:
清理臨時檔案
忽略訊號
清理臨時檔案:
trap命令作為一個例子,下面展示了如何可以刪除一些檔案,然後退出,如果有人試圖從終端中止程式:
trap "rm -f $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 2
執行shell程式,這個陷阱的角度,這兩個檔案work1$$ 和 dataout$$將被自動刪除,如果程式接收訊號數為2。
因此,使用者中斷執行,如果執行的程式後,這個陷阱你可以放心,這兩個檔案將被清理。 exit 命令如下 rm 是必要的,因為沒有它的執行將繼續在節目中的一點,它離開時收到訊號。
1號訊號產生掛斷:要麼有人故意掛斷線路或線路被意外斷開。
您可以修改前面的陷阱也刪除指定的檔案,在這種情況下,兩個訊號訊號1號添加到列表:
$ trap "rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 1 2
現在,這些檔案將被刪除,如果該行被掛了,或者按Ctrl c鍵被按下。
來捕獲指定的命令必須用引號括起來,如果它們包含一個以上的命令。另外請注意,在 shell 命令列掃描 trap 命令得到執行,並再次當一個所列出的的訊號被接收的時間。
WORKDIR 值 $$ 所以在前面的例子中,將被取代 trap 命令執行的時間。如果你想這種替代發生在收到訊號1或2的時間你可以把單引號內的命令:
$ trap 'rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit' 1 2
忽略訊號:
如果陷阱列出的命令是空的,指定的訊號接收時,將被忽略。例如,下面的命令:
$ trap '' 2
指定的中斷訊號是被忽略的。你可能要忽略某些訊號時進行一些操作,不希望打斷。可以指定多個訊號被忽略如下:
$ trap '' 1 2 3 15
注意,第一個參數必須被指定為一個訊號被忽略,而不是相當於寫入下面的內容,它具有獨立的含義也各有:
$ trap 2
如果你忽略了一個訊號,所有的子shell也忽略該訊號。不過,如果指定要採取的行動在收到的訊號,所有的子shell仍然會在收到該訊號的預設操作。
重設陷阱:
當你改變了預設在收到訊號後應採取的動作,你可以改變它回來的陷阱,如果你只是省略第一個參數;
$ trap 1 2
複位應採取的動作收到訊號1或2 返回預設。