trap命令用於指定在接收到訊號後將要採取的動作。常見的用途是在指令碼程式被中斷時完成清理工作。不過,這次我遇到它,是因為客戶有個需求:從終端訪問伺服器的使用者,其登陸伺服器後會自動運行某個命令,例如開啟應用(命令寫在.bashrc等檔案中),最後退出,並中斷連線;期間是不能允許其使用Ctrl+C等中斷退出應用,而回到Shell環境,否則可能會帶來安全問題。
當然,解決的方式有很多,如在應用中屏蔽中斷訊號、使用chroot方式訪問等。但這些方法都有一些限制,如需要修改應用,讓telnet等支援chroot方式(ssh可支援chroot)等。而使用trap也是一種比較好的解決方案。
一、關於訊號
曆史上,shell總是用數字來代表訊號,而新的指令碼程式應該使用訊號的名字,它們儲存在用#include命令包含進來的signal.h標頭檔中,在使用訊號名時需要省略SIG首碼。
kill和trap等都可以看到訊號編號及其關聯的名稱。“訊號”是指那些被非同步發送到一個程式的事件。預設情況下,它們通常會終止一個程式的運行。
# trap -l1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR213) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+136) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+540) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+944) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+1348) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-1352) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-956) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-560) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-164) SIGRTMAX
二、trap 的使用
1、運行格式
trap命令的參數分為兩部分,前一部分是接收到指定訊號時將要採取的行動,後一部分是要處理的訊號名。
trap command signal
它有三種形式分別對應三種不同的訊號回應方式。
第一種:
trap "commands" signal-list
當指令碼收到signal-list清單內列出的訊號時,trap命令執行雙引號中的命令。
第二種:
trap signal-list
trap不指定任何命令,接受訊號的預設操作,預設操作是結束進程的運行。
第三種:
trap " " signal-list
trap命令指定一個空命令串,允許忽視訊號,我們用到的就是這一種。
※ 請記住,指令碼程式通常是以從上到下的順序解釋執行的,所以必須在你想保護的那部分代碼以前指定trap命令。
2、測試
按照使用者的要求,我們需要屏蔽的是HUP INT QUIT TSTP幾個訊號。所以,可以運行:
# trap "" HUP INT QUIT TSTP
這個時候,可以試試開啟一個持續的命令,然後中斷其運行,例如:
# tail -f /var/log/messages
接著,試試用Ctrl+C 或 Ctrl+\ 來中斷試試,會程式是不會退出的。
3、恢複訊號
如果想恢複的話,可以用Ctrl+Z把程式放到後台,然後運行:
# trap : HUP INT QUIT TSTP
然後,用ps -ef看看其PID號,bg 1讓程式繼續運行,最後用kill 殺掉即可。
4、其他
您也可以試試運行:
# trap "echo 'Hello World' " HUP INT QUIT TSTP
這樣,當您運行Ctrl+C 等中斷時,會自動運行echo命令,結果就是現實Hello World字串:
# tail -f /var/log/messagesMay 18 16:57:54 192.168.228.153 dhcpd: DHCPREQUEST for 192.168.228.221 from 00:1d:72:92:d4:68 via eth0May 18 16:57:54 192.168.228.153 dhcpd: DHCPACK on 192.168.228.221 to 00:1d:72:92:d4:68 via eth0[root@mail ~]# Hello World
※ 注意,這方式並不能屏蔽中斷,敲入Ctrl+C 等資訊後,仍以預設行為動作的,也就是退出程式,僅會再運行一個額外的命令而已。
三、附錄
1、中斷按鍵
不同的終端類型、Shell版本其中斷的按鍵是不同的,甚至還可以自訂,這可通過stty命令查詢:
# stty -aspeed 38400 baud; rows 30; columns 111; line = 0;intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ; eol2 = ; start = ^Q; stop = ^S;susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbelopost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
^就是Ctrl的縮寫。
2、訊號詳情
名稱 預設動作 說明SIGHUP 終止進程 終端線路掛斷SIGINT 終止進程 中斷進程SIGQUIT 建立CORE檔案 終止進程,並且產生core檔案SIGILL 建立CORE檔案 非法指令SIGTRAP 建立CORE檔案 跟蹤自陷SIGBUS 建立CORE檔案 匯流排錯誤SIGSEGV 建立CORE檔案 段非法錯誤SIGFPE 建立CORE檔案 浮點異常SIGIOT 建立CORE檔案 執行I/O自陷SIGKILL 終止進程 殺死進程SIGPIPE 終止進程 向一個沒有讀進程的管道寫資料SIGALARM 終止進程 計時器到時SIGTERM 終止進程 軟體終止訊號SIGSTOP 停止進程 非終端來的停止訊號SIGTSTP 停止進程 終端來的停止訊號SIGCONT 忽略訊號 繼續執行一個停止的進程SIGURG 忽略訊號 I/O緊急訊號SIGIO 忽略訊號 描述符上可以進行I/OSIGCHLD 忽略訊號 當子進程停止或退出時通知父進程SIGTTOU 停止進程 後台進程寫終端SIGTTIN 停止進程 後台進程讀終端SIGXGPU 終止進程 CPU時限逾時SIGXFSZ 終止進程 檔案長度過長SIGWINCH 忽略訊號 視窗大小發生變化SIGPROF 終止進程 統計分布圖用計時器到時SIGUSR1 終止進程 使用者定義訊號1SIGUSR2 終止進程 使用者定義訊號2SIGVTALRM 終止進程 虛擬計時器到時