UNIX 信號(hào)和 Traps

2018-08-12 22:12 更新

信號(hào)和 Traps

信號(hào)是發(fā)送給程序的軟件中斷,表明已發(fā)生的重要事件。這些事件的范圍可以是從用戶請(qǐng)求到非法內(nèi)存訪問(wèn)錯(cuò)誤。這些信號(hào),如中斷信號(hào),表明用戶要求程序做一些非一般流程控制下的事情。

以下是一些你可能會(huì)遇到的并且需要在程序中使用的常見(jiàn)信號(hào):

信號(hào)名 信號(hào)值 描述
SIGHUP 1 控制終端意外終止或者是控制進(jìn)程結(jié)束時(shí)發(fā)出
SIGINT 2 用戶發(fā)送一個(gè)中斷信號(hào)時(shí)發(fā)出(Ctrl+C)。
SIGQUIT 3 用戶發(fā)送一個(gè)退出信號(hào)時(shí)發(fā)出(Ctrl+D)。
SIGFPE 8 當(dāng)非法的數(shù)學(xué)操作執(zhí)行時(shí)發(fā)出。
SIGKILL 9 一個(gè)進(jìn)程獲取到此信號(hào),它必須立即退出,并且不能進(jìn)行任何清除操作。
SIGALRM 14 時(shí)鐘信號(hào)(用于定時(shí)器)
SIGTERM 15 軟件終止信號(hào)(kill 命令缺省產(chǎn)生此信號(hào))。

信號(hào)列表

有一個(gè)簡(jiǎn)單的方法可以列出你的系統(tǒng)所支持的所有信號(hào)。僅僅用命令 kill -l 就可以顯示系統(tǒng)所有支持的信號(hào):

    $ kill -l
     1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
     5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
     9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
    13) SIGPIPE     14) SIGALRM     15) SIGTERM     16) SIGSTKFLT
    17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
    21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU
    25) SIGXFSZ     26) SIGVTALRM   27) SIGPROF     28) SIGWINCH
    29) SIGIO       30) SIGPWR      31) SIGSYS      34) SIGRTMIN
    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3  38) SIGRTMIN+4
    39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
    43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
    47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
    51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
    55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7  58) SIGRTMAX-6
    59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
    63) SIGRTMAX-1  64) SIGRTMAX

Solaris, HP-UX 和 Linux 之間實(shí)際的信號(hào)列表會(huì)有所不同。

默認(rèn)動(dòng)作

每一個(gè)信號(hào)都有一個(gè)與之相隨的默認(rèn)動(dòng)作。一個(gè)信號(hào)的默認(rèn)動(dòng)作是當(dāng)腳本或程序接收到一個(gè)信號(hào)時(shí),它的執(zhí)行表現(xiàn)。

這些可能的默認(rèn)動(dòng)作是:

  • 終止進(jìn)程。

  • 忽略信號(hào)。

  • 內(nèi)核映像轉(zhuǎn)儲(chǔ)。當(dāng)收到信號(hào)時(shí),此動(dòng)作將創(chuàng)建一個(gè)稱為 core 的文件,其包含進(jìn)程的內(nèi)存映像。

  • 停止進(jìn)程。

  • 繼續(xù)停止的進(jìn)程。

發(fā)送信號(hào)

有幾種向程序或者腳本傳遞信號(hào)的方法。其中用戶最常見(jiàn)的是在正在運(yùn)行的腳本的時(shí)候,按下 Ctrl+C 或者 INTERRUPT 鍵。

當(dāng)你按下 Ctrl+C 鍵,信號(hào) SIGINT 被發(fā)送到腳本中,根據(jù)之前定義的默認(rèn)動(dòng)作,腳本將會(huì)被終止。

另外一種常見(jiàn)的傳送信號(hào)的方法是使用 kill 命令,其語(yǔ)法如下所示:

    $ kill -signal pid

這里的 signal 要么是信號(hào)值,要么是信號(hào)名稱。 pid 是信號(hào)要發(fā)送到的進(jìn)程的 ID。 例如:

    $ kill -1 1001

發(fā)送 HUP 信號(hào)(即意外終止信號(hào))到運(yùn)行進(jìn)程 ID 為 1001 的程序。 用下面的命令來(lái)發(fā)送一個(gè) kill 信號(hào)到同樣的進(jìn)程:

    $ kill -9 1001

這條命令會(huì)殺死運(yùn)行進(jìn)程 ID 為 1001 的程序。

捕獲信號(hào)

當(dāng)一個(gè) Shell 程序正在執(zhí)行的過(guò)程中,你在終端按下了 Ctrl+C 或 Break 鍵,通常情況下,程序會(huì)立即終止,并且你的命令提示返回。但這可能并不總是你所期望的。例如,這可能會(huì)留下一堆未清理的臨時(shí)文件。

捕獲這些信號(hào)是很容易的,捕獲命令(trap)的語(yǔ)法如下:

    $ trap commands signals

這里的 commands 可以是任何有效的 UNIX 命令,甚至可以是一個(gè)用戶定義的函數(shù)。

signals 可以是一個(gè)你想捕獲的任何數(shù)量信號(hào)的列表。

在 Shell 腳本中,trap 有三種常見(jiàn)的用途:

  1. 清除臨時(shí)文件
  2. 忽略信號(hào)

清除臨時(shí)文件

作為 trap 命令的一個(gè)例子,下面的命令展示了,如果有人試圖從終端中止程序時(shí),你如何先刪除一些文件,然后退出:

    $ trap "rm -f $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 2

如果程序收到了信號(hào)值為 2 的信號(hào),trap 命令將會(huì)被執(zhí)行。從 Shell 程序上執(zhí)行 trap 的這一點(diǎn)開(kāi)始,work1$$ 和 dataout$$ 這兩個(gè)文件會(huì)自動(dòng)被刪除。

所以如果用戶中斷程序的運(yùn)行,這個(gè) trap 將會(huì)被執(zhí)行,你可以確保這兩個(gè)文件將被清理掉。rm 后面的這個(gè) exit 命令,它的存在是必要的。如果沒(méi)有它,程序會(huì)在它中斷點(diǎn)(也就是信號(hào)接收的時(shí)刻)繼續(xù)執(zhí)行。

信號(hào)值 1 是由掛斷產(chǎn)生的:要么是有人故意掛斷終端或者是終端被意外斷開(kāi)。

在這種情況下,把信號(hào)值 1 增加到信號(hào)列表中,你可以通過(guò)這樣修改上面的 trap 命令,從而刪除那兩個(gè)指定的文件:

    $ trap "rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 1 2

現(xiàn)在,如果終端被掛起或者是 Ctrl+C 被按下,這些文件將被刪除。

指定的 trap 命令如果包含多個(gè)命令,那么它們必須括在引號(hào)中。還要注意,當(dāng) trap 命令執(zhí)行時(shí),shell 會(huì)掃描一遍命令行,當(dāng)接收到信號(hào)列表的其中一個(gè)信號(hào)時(shí),也會(huì)再執(zhí)行一次掃描。

所以在上面的例子中,當(dāng) trap 命令執(zhí)行后,WORKDIR 和 $$ 的值將會(huì)被替換。如果你想要這種替換僅僅發(fā)生在信號(hào)值 1 或者 2 接收到的時(shí)候,你可以用單引號(hào)把多個(gè)命令引起來(lái):

    $ trap 'rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit' 1 2

忽略信號(hào)

如果 trap 命令的 command 字段是空的,那么當(dāng)接收到指定的信號(hào)后,信號(hào)將被忽略。例如下面的一個(gè)命令:

    $ trap '' 2

指定的中斷信號(hào)將被忽略。當(dāng)執(zhí)行某些可能不想被打斷的操作時(shí),你可能會(huì)想忽略掉些特定的信號(hào)。按如下所示,你可以指定要忽略的多個(gè)信號(hào):

    $ trap '' 1 2 3 15

注意,如果要一個(gè)信號(hào)被忽略掉,那么第一個(gè)參數(shù)必須是指定的空,它不等同于如下的命令,下面的命令有自己?jiǎn)为?dú)的意義:

    $ trap  2

如果你忽略了一個(gè)信號(hào),那么你所有的子 Shell 也會(huì)忽略此信號(hào)。然而,如果你指定了接收一個(gè)信號(hào)所采取的動(dòng)作,那么所有的子 shell 接收到此信號(hào)后會(huì)采取相同動(dòng)作。

重置 Traps

當(dāng)你改變了信號(hào)接收后的默認(rèn)動(dòng)作,你可以通過(guò)一個(gè)簡(jiǎn)單的省略第一個(gè)參數(shù)的 trap 命令將默認(rèn)動(dòng)作重置回來(lái)。

那么命令

    $ trap 1 2

將信號(hào) 1 和 2 接收后采取的動(dòng)作重置為其原有的默認(rèn)動(dòng)作。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)