我們ping一個主機,然後按下ctrl+c
那麼就會終止這個ping動作,如下圖:
可是如果使用一個迴圈來逐個ping不同主機,你再按下ctrl+c
就會發現停不下來,直到迴圈完成,如下圖:
#!/bin/bash
NETWORK=172.16.42.
# -W 表示超時時長 -c 是傳送幾個ping包
for IP in {1..20}; do
ping -W 1 -c 10 ${NETWORK}${IP}
done
指令碼沒有停止而是依然繼續執行,但是你發現172.16.42.1是通的,而且我們透過-c引數應該是ping 10次,當完成第5次ping的時候,我們按下ctrl+c
它就不再ping這個地址,而是開始ping 172.16.42.2這個地址。這就是ctrl+c
的真正含義,它的作用是終止當前正在執行的操作,指令碼中迴圈20次,每次執行一個ping操作,所以ctrl+c
僅僅終止的是其中一個ping操作而不是整個指令碼。
不過這麼解釋並不完全正確,因為你要知道ctrl+c
是傳送中斷訊號,到底是應該終止ping操作還是這個指令碼,取決於捕捉到這個中斷訊號的程式,如果是ping捕捉到了,那麼就終止ping操作;如果是執行這個指令碼的程式捕捉到就終止這個指令碼的執行。那麼我們如何設定捕捉一個訊號呢?就使用trap
這個內建的shell命令。
trap -l
顯示系統訊號[1],kill -l
也是可以顯示的。
trap命令不能捕捉SIGKILL和SIGTERM這兩個訊號。捕捉訊號的目的是一旦訊號到達我們針對訊號做什麼處理,如果捕捉SIGKILL並且你修改了行為,這就意味著這個程式刀槍不入了,這顯然不行。一般我們捕捉SIGHUP、SIGINT等。
針對上面的例子如何修改呢?
#!/bin/bash
# 捕捉INT,然後執行exit 1,該命令通常寫在指令碼第一行
trap 'exit 1' INT
NETWORK=172.16.42.
# -W 表示超時時長 -c 是傳送幾個ping包
for IP in {1..20}; do
ping -W 1 -c 10 ${NETWORK}${IP}
done
再次執行這個指令碼那麼依然會執行迴圈,但是trap並不執行而是一直等著訊號發生,我們使用的ctrl+c
其實就是SIGINT訊號。這個指令碼的含義就是shell捕捉訊號,所以shell捕捉到以後就會執行響應動作,我們這裡是trap 'exit 1' INT
捕捉SIGINT然後執行exit 1
,當shell執行這個命令時也就意味著退出了,所以無論for迴圈是否執行完畢它都隨著指令碼的退出而終止。
如果你想讓捕捉訊號時做更多操作,你可以使用函式的方式,如下程式碼:
#!/bin/bash
trap 'sig_handler' INT
sig_handler(){
echo "Quit"
exit 1
}
NETWORK=172.16.42.
# -W 表示超時時長 -c 是傳送幾個ping包
for IP in {1..20}; do
ping -W 1 -c 10 ${NETWORK}${IP}
done
也就是突然終止後需要做一些收尾的清理操作,你就可以透過上面自定義一個函式來執行。
訊號是程式間通訊的一種方式 ↩︎