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