信號是一種進程間的通信機制,它給應(yīng)用程序提供一種異步的軟件中斷,是應(yīng)用程序有機會接受其他程序活終端發(fā)送的命令 (即信號)。應(yīng)用程序收到信號后,有三種處理方式:忽略,默認,捕捉。該進程收到一個信號后,會檢查對該信號的處理機制。如果是 SIG_IGN
,就會忽略該信號;如果是 SIG_DFT
,則會采用系統(tǒng)默認的處理動作,通常是終止進程或忽略該信號;如果給該信號指定了一個處理函數(shù) (捕捉),則會中斷當(dāng)前進程正在執(zhí)行的任務(wù),轉(zhuǎn)而去執(zhí)行該信號的處理函數(shù),返回后在繼續(xù)執(zhí)行被中斷的任務(wù)。
在有些情況下,我們不希望自己的 shell 腳本在運行時刻被中斷,比如說我們寫的 shell 腳本設(shè)為某一用戶的默認 shell,使這一用戶進入系統(tǒng)后只能做某一項工作,如數(shù)據(jù)庫備份,我們可不希望用戶使用 Ctrl+C
鍵便能進入到 shell 狀態(tài),做我們不希望看到的事情,這便用到了信號處理。
以下是一些常見的信號:
```信號名稱 信號數(shù) 說明 SIGHUP 1 本信號在用戶終端連接 (正?;蚍钦? 結(jié)束時發(fā)出,通常是在終端的控制進程結(jié)束時,通知同一 session 內(nèi)的各個作業(yè),這時它們與控制終端不再關(guān)聯(lián)。登錄 Linux 時,系統(tǒng)會分配給登錄用戶一個終端 (Session)。在這個終端運行的所有程序,包括前臺進程組和后臺進程組,一般都屬于這個 Session。當(dāng)用戶退出 Linux 登錄時,前臺進程組和后臺有對終端輸出的進程將會收到 SIGHUP 信號。這個信號的默認操作為終止進程,因此前臺進程組和后臺有終端輸出的進程就會中止。對于與終端脫離關(guān)系的守護進程,這個信號用于通知它重新讀取配置文件。 SIGINT 2 程序終止 (interrupt) 信號,在用戶鍵入 INTR 字符 (通常是 Ctrl+C) 時發(fā)出 SIGQUIT 3 和 SIGINT 類似,但由 QUIT 字符 (通常是 Ctrl /) 來控制。進程在因收到 SIGQUIT 退出時會產(chǎn)生 core 文件,在這個意義上類似于一個程序錯誤信號。 SIGFPE 8 在發(fā)生致命的算術(shù)運算錯誤時發(fā)出。不僅包括浮點運算錯誤,還包括溢出及除數(shù)為 0 等其它所有的算術(shù)的錯誤。 SIGKILL 9 用來立即結(jié)束程序的運行。本信號不能被阻塞,處理和忽略。 SIGALRM 14 時鐘定時信號,計算的是實際的時間或時鐘時間。alarm 函數(shù)使用該信號 SIGTERM 15 程序結(jié)束 (terminate) 信號,與 SIGKILL 不同的是該信號可以被阻塞和處理。通常用來要求程序自己正常退出。shell 命令 kill 缺省產(chǎn)生這個信號。
**捕獲信號**
當(dāng)按下了 `Ctrl+C` 鍵或 `break` 鍵在終端一個 shell 程序的執(zhí)行過程中,正常程序?qū)⒘⒓唇K止,并返回命令提示符。這可能并使總是可取的,例如,你可能最終留下了一堆臨時文件,將不會清理。
捕獲這些信號是很容易的,`trap` 命令的語法如下:
`\#trap commands signals`
這里的 `commands` 可以是任何有效的 linux 命令,或一個用戶定義的函數(shù),信號可以是任意數(shù)量的信號,你想來捕獲的列表。
- trap 捕捉到信號之后,可以有三種反應(yīng)方式:
1. 執(zhí)行一段程序來處理這一信號
2. 接受信號的默認操作
3. 忽視這一信號
- trap 對上面三種方式提供了三種基本形式:
- 第一種形式的 `trap` 命令在 shell 接收到 signal list 清單中數(shù)值相同的信號時,將執(zhí)行雙引號中的命令串。
`trap 'commands' signal-list`
`trap "commands" signal-list`
- 為了恢復(fù)信號的默認操作,使用第二種形式的 trap 命令
`trap signal-list`
- 第三種形式的 trap 命令允許忽視信號
`trap " " signal-list`
注意:
1. 對信號 11(段違例) 不能捕捉,因為 shell 本身需要捕捉該信號去進行內(nèi)存的轉(zhuǎn)儲。
2. 在 trap 中可以定義對信號 0 的處理 (實際上沒有這個信號),shell 程序在其終止 (如執(zhí)行 exit 語句) 時發(fā)出該信號。
3. 在捕捉到 `signal-list` 中指定的信號并執(zhí)行完相應(yīng)的命令之后,如果這些命令沒有將 shell 程序終止的話,shell 程序?qū)⒗^續(xù)執(zhí)行收到信號時所執(zhí)行的命令后面的命令,這樣將很容易導(dǎo)致 shell 程序無法終止。另外,在 `trap` 語句中,單引號和雙引號是不同的,當(dāng) shell 程序第一次碰到 `trap` 語句時,將把 `commands` 中的命令掃描一遍。此時若 `commands` 是用單引號括起來的話,那么 shell 不會對 `commands` 中的變量和命令進行替換,否則 `commands` 中的變量和命令將用當(dāng)時具體的值來替換。
**trap 命令用于指定在接收到信號后將要采取的動作。常見的用途是在腳本程序被中斷時完成清理工作。**
測試案例:
按照用戶的要求,我們需要屏蔽的是 `HUP INT QUIT TSTP` 幾個信號。所以,可以運行:
`\#trap “”HUP INT QUIT TSTP`
這個時候,可以試試打開一個持續(xù)的命令,然后中斷其運行,例如:
`\#tail -f /var/log/messages`
接著,試試用 `Ctrl+C` 或 `Ctrl+\` 來中斷試試,該進程是不會退出的。
**恢復(fù)信號**
如果想恢復(fù)的話,可以用 `Ctrl+Z` 吧進程放到后臺,然后運行:
`\#trap :HUP INT QUIT TSTP`
然后,用 `#ps -ef` 看看其 PID 號,`bg 1` 讓程序繼續(xù)運行,最后用 kill 殺掉即可。
**其他**
可以試試運行:
`\#trap “echo ‘hello world’” HUP INT QUIT TSTP`
這樣,當(dāng)你運行 `Ctrl+C` 等中斷時,會自動運行 `echo` 命令,結(jié)果就是實現(xiàn) helloworld 字符串。
**引用**
`\#tail -f /var/log/messages`
注意,這方式并不能屏蔽中斷,按下 `Ctrl+C` 鍵仍然會退出程序,僅會再運行一個額外的命令而已。