在本章中,我们将详细讨论Unix中的信号和Trap。
信号是发送到程序的软件中断,以指示发生了重要事件。事件可能会有所不同,从用户请求到非法的内存访问错误。某些信号(例如中断信号)表明用户已要求程序执行不在常规控制流程中的操作。
下表列出了您可能在程序中遇到并想要使用的常见信号-
信号名称 | 信号编号 | 描述 |
---|---|---|
SIGHUP | 1个 | 在控制终端上挂断或控制过程终止 |
SIGINT | 2 | 如果用户发送中断信号(Ctrl + C),则发出 |
SIGQUIT | 3 | 如果用户发送退出信号(Ctrl + D),则发出 |
SIGFPE | 8 | 如果尝试非法数学运算,则发出 |
SIGKILL | 9 | 如果某个进程收到此信号,则必须立即退出并且将不执行任何清理操作 |
SIGALRM | 14 | 闹钟信号(用于计时器) |
SIGTERM | 15 | 软件终止信号(默认为终止发送) |
信号清单
有一种简单的方法可以列出系统支持的所有信号。只需发出kill -l命令,它将显示所有支持的信号-
$ 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之间有所不同。
默认动作
每个信号都有与之关联的默认操作。信号的默认操作是脚本或程序在收到信号时执行的操作。
一些可能的默认操作是-
- 终止过程。
- 忽略信号。
- 转储核心。这将创建一个名为core的文件,其中包含接收到信号时进程的内存映像。
- 停止该过程。
- 继续停止的过程。
发送信号
有几种向程序或脚本传递信号的方法。最常见的一种是用户在执行脚本时键入CONTROL-C或INTERRUPT键。
当您按Ctrl + C键时,SIGINT将发送到脚本,并且按照定义的默认操作脚本终止。
传递信号的另一种常见方法是使用kill命令,其语法如下-
$ kill -signal pid
这里,signal是要传递的信号的编号或名称,而pid是信号应发送至的进程ID。例如-
$ kill -1 1001
上面的命令将HUP或挂断信号发送到以进程ID 1001运行的程序。要将终止信号发送到同一进程,请使用以下命令-
$ kill -9 1001
这将终止以进程ID 1001运行的进程。
诱捕信号
当您在执行Shell程序期间在终端上按Ctrl + C或Break键时,通常该程序会立即终止,并返回命令提示符。这可能并不总是令人满意的。例如,您可能最终会留下一堆无法清除的临时文件。
捕获这些信号非常容易,并且trap命令具有以下语法-
$ trap commands signals
这里的命令可以是任何有效的Unix命令,甚至是用户定义的函数,而signal可以是要捕获的任意数量的信号的列表。
在shell脚本中Trap有两种常见用法-
- 清理临时文件
- 忽略信号
清理临时文件
作为trap命令的示例,以下内容显示了如何删除某些文件,然后在有人尝试从终端中止程序时退出并退出-
$ trap "rm -f $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 2
从shell程序中执行该Trap的那一刻起*,如果程序接收到信号编号2 ,则两个文件work1 $$*和*dataout $$*将自动删除。
因此,如果用户在执行此Trap后中断了程序的执行,则可以确保将清除这两个文件。紧随rm之后的退出命令是必要的,因为如果没有rm,则它将在程序中继续执行,直到接收到信号时它就停止了。
产生1号信号进行挂断。有人故意将线路挂断,或者线路意外断开连接。
您可以通过将信号编号1添加到信号列表来修改前面的Trap以在这种情况下也删除两个指定的文件-
$ trap "rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 1 2
现在,如果挂断该行或按下Ctrl + C键,将删除这些文件。
如果指定的Trap命令包含多个命令,则必须用引号引起来。另请注意,在执行trap命令时以及接收到列出的信号之一时,shell会扫描命令行。
因此,在前面的示例中,将在执行Trap命令时替换WORKDIR和$$的值。如果您希望在接收到信号1或2时进行这种替换,则可以将命令放在单引号中-
$ trap 'rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit' 1 2
忽略信号
如果列出的Trap命令为空,则在接收到指定的信号时将忽略该信号。例如,命令-
$ trap '' 2
这指定将忽略中断信号。在执行您不想被中断的操作时,您可能想忽略某些信号。您可以指定多个要忽略的信号,如下所示:
$ trap '' 1 2 3 15
请注意,必须为忽略信号指定第一个参数,这并不等同于编写以下参数,后者具有其自身的单独含义-
$ trap 2
如果忽略信号,则所有子Shell程序也会忽略该信号。但是,如果您指定要在收到信号时采取的措施,则所有子Shell程序仍将在收到该信号时采取默认措施。
重置Trap
更改了要在收到信号后采取的默认操作后,如果您只是省略了第一个参数,则可以使用Trap将其再次更改。所以-
$ trap 1 2
这会将收到信号1或2时要采取的操作重置为默认值。