trap
指定在接收到信号後将要采取的動作
補充說明
trap指令 用于指定在接收到信号後将要采取的動作,常見的用途是在腳本程式被中斷時完成清理工作。當shell接收到sigspec指定的信号時,arg參數(指令)将會被讀取,并被執行。例如:
trap "exit 1" HUP INT PIPE QUIT TERM
表示當shell收到HUP INT PIPE QUIT TERM這幾個指令時,目前執行的程式會讀取參數“exit 1”,并将它作為指令執行。
文法
trap -[lp] [[arg] sigspec ...]
選項參數說明
如果arg參數預設或者為“-”,每個接收到的sigspec信号都将會被重置為它們進入shell時的值;
如果arg是空字元串每一個由sigspec指定的信号都會被shell和它所調用的指令忽略;
如果有-p選項而沒有提供arg參數則會列印所有與sigspec指定信号相關聯的的trap指令;
如果沒有提供任何參數或者僅有-p選項,trap指令将會列印與每一個信号有關聯的指令的清單;
-l選項的作用是讓shell列印一個指令名稱和其相對應的編号的清單。
每個sigspec信号都是是以名字或者編号的形式定義在signal.h頭檔案中,信号的名字是不區分大小寫的,其字首SIG是可選的,如果某個信号是 EXIT(0),那麼arg指定的指令将會在shell上執行退出指令時執行(If a sigspec is EXIT (0) the command arg is executed on exit from the shell),如果sigspec是DEBUG,那麼arg指定的指令将會在以下每個指令執行之前執行:
簡單指令,for語句,case語句,select指令,算法指令,在函數内的第一條指令。
更多trap debug的使用可以參考extdebug選項說明。
如果sigspec是ERR,arg參數指定的指令将會在任何簡單命名執行完後傳回值為非零值時執行,但是也有以下例外情況:
如果執行失敗的指令是緊跟在while或者until關鍵字之後的一組指令中的一部分時
如果執行失敗的指令是if測試語句的一部分時,是 && 和 ||連接配接的清單中的一部分時
如果執行失敗的指令的傳回值是被取反過的(通過!操作符)
在以上情況中如果sigspec是ERR,arg指令不會執行,這些規則同樣适用于errexit選項。如果sigspec是RETURN,arg指定的指令在每次shell函數或者腳本用”.”或者内置的指令執行完成後執行,在shell入口處被忽略的指令 是沒法被trap和reset的,被trap的信号,在建立的子程序中使用時會在子程序被建立時被重置為原始的值。如果trap使用的sigspec信号 是invalid的信号則trap指令傳回false(失敗),否則傳回成功(true)。
信号
信号是一種程序間通信機制,它給應用程式提供一種異步的軟體中斷,使應用程式有機會接受其他程式活終端發送的指令(即信号)。應用程式收到信号後,有三種處理方式:忽略,預設,或捕捉。程序收到一個信号後,會檢查對該信号的處理機制。如果是SIG_IGN,就忽略該信号;如果是SIG_DFT,則會采用系統預設的處理動作,通常是終止程序或忽略該信号;如果給該信号指定了一個處理函數(捕捉),則會中斷目前程序正在執行的任務,轉而去執行該信号的處理函數,傳回後再繼續執行被中斷的任務。
在有些情況下,我們不希望自己的shell腳本在運作時刻被中斷,比如說我們寫得shell腳本設為某一使用者的預設shell,使這一使用者進入系統後隻能作某一項工作,如資料庫備份, 我們可不希望使用者使用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腳本中的陷阱有三種常見的用途:
清理臨時檔案
忽略信号1、清理臨時檔案:
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
2、忽略信号:
如果陷阱列出的指令是空的,指定的信号接收時,将被忽略。例如,下面的指令:
$ trap '' 2
指定的中斷信号是被忽略的。你可能要忽略某些信号時進行一些操作,不希望打斷。可以指定多個信号被忽略如下:
$ trap '' 1 2 3 15
注意,第一個參數必須被指定為一個信号被忽略,而不是相當于寫入下面的内容,它具有獨立的含義也各有:
$ trap 2
如果你忽略了一個信号,所有的子shell也忽略該信号。不過,如果指定要采取的行動在收到的信号,所有的子shell仍然會在收到該信号的預設操作。
3、重設陷阱:
當你改變了預設在收到信号後應采取的動作,你可以改變它回來的陷阱,如果你隻是省略第一個參數;
$ trap 1 2
複位應采取的動作收到信号1或2傳回預設。