Unix 简明教程

Unix / Linux - Signals and Traps

在本章中,我们将详细讨论 Unix 中的信号和陷阱。

In this chapter, we will discuss in detail about Signals and Traps in Unix.

信号是发送到程序中的软件中断,用于指明重要事件已发生。事件可以从用户请求到非法内存访问错误。一些信号(例如中断信号)表明用户已要求程序执行不在通常控制流中的操作。

Signals are software interrupts sent to a program to indicate that an important event has occurred. The events can vary from user requests to illegal memory access errors. Some signals, such as the interrupt signal, indicate that a user has asked the program to do something that is not in the usual flow of control.

下表列出了你可能遇到的和希望在程序中使用的常见信号 -

The following table lists out common signals you might encounter and want to use in your programs −

Signal Name

Signal Number

Description

SIGHUP

1

Hang up detected on controlling terminal or death of controlling process

SIGINT

2

Issued if the user sends an interrupt signal (Ctrl + C)

SIGQUIT

3

Issued if the user sends a quit signal (Ctrl + D)

SIGFPE

8

Issued if an illegal mathematical operation is attempted

SIGKILL

9

If a process gets this signal it must quit immediately and will not perform any clean-up operations

SIGALRM

14

Alarm clock signal (used for timers)

SIGTERM

15

Software termination signal (sent by kill by default)

List of Signals

有一种简单的方法可以列出系统支持的所有信号。只需发出 kill -l 命令,它将显示所有受支持的信号 -

There is an easy way to list down all the signals supported by your system. Just issue the kill -l command and it would display all the supported signals −

$ 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 而异。

The actual list of signals varies between Solaris, HP-UX, and Linux.

Default Actions

每个信号都有与其关联的默认操作。信号的默认操作是脚本或程序在接收到信号时执行的操作。

Every signal has a default action associated with it. The default action for a signal is the action that a script or program performs when it receives a signal.

一些可能的默认操作 -

Some of the possible default actions are −

  1. Terminate the process.

  2. Ignore the signal.

  3. Dump core. This creates a file called core containing the memory image of the process when it received the signal.

  4. Stop the process.

  5. Continue a stopped process.

Sending Signals

有几种将信号传递给程序或脚本的方法。最常见的方法之一是让用户在脚本执行时键入 CONTROL-CINTERRUPT key

There are several methods of delivering signals to a program or script. One of the most common is for a user to type CONTROL-C or the INTERRUPT key while a script is executing.

当您按下 Ctrl+C 键时,一条 SIGINT 被发送到脚本中,并且根据定义的默认操作脚本终止。

When you press the Ctrl+C key, a SIGINT is sent to the script and as per defined default action script terminates.

发出信号的另一种常用方法是使用 kill command ,其语法如下 −

The other common method for delivering signals is to use the kill command, the syntax of which is as follows −

$ kill -signal pid

其中 signal 是要发送的信号的号码或名称, pid 是要向其发送信号的进程 ID。例如 −

Here signal is either the number or name of the signal to deliver and pid is the process ID that the signal should be sent to. For Example −

$ kill -1 1001

上述命令将 HUP 或挂起信号发送到正在使用 process ID 1001 运行的程序。要向同一进程发送终止信号,请使用以下命令 −

The above command sends the HUP or hang-up signal to the program that is running with process ID 1001. To send a kill signal to the same process, use the following command −

$ kill -9 1001

这将杀死正在使用 process ID 1001 运行的进程。

This kills the process running with process ID 1001.

Trapping Signals

当你在终端执行 shell 程序时按下 Ctrl+C 或 Break 键时,通常该程序会立即终止,并且你的命令提示符会返回。这可能并不总是需要的。例如,你最终可能会留下一些未清理的临时文件。

When you press the Ctrl+C or Break key at your terminal during execution of a shell program, normally that program is immediately terminated, and your command prompt returns. This may not always be desirable. For instance, you may end up leaving a bunch of temporary files that won’t get cleaned up.

捕获这些信号非常容易,并且陷阱命令具有以下语法:

Trapping these signals is quite easy, and the trap command has the following syntax −

$ trap commands signals

在这里,command 可以是任何有效的 Unix 命令,甚至可以是用户定义的函数,而 signal 可能是你想要捕获的任何数量信号的列表。

Here command can be any valid Unix command, or even a user-defined function, and signal can be a list of any number of signals you want to trap.

在 shell 脚本中,trap 有两种常见用法:

There are two common uses for trap in shell scripts −

  1. Clean up temporary files

  2. Ignore signals

Cleaning Up Temporary Files

作为 trap 命令的示例,以下显示了当有人尝试从终端中止程序时,如何删除一些文件并随后退出:

As an example of the trap command, the following shows how you can remove some files and then exit if someone tries to abort the program from the terminal −

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

从执行此陷阱的 shell 程序开始,如果程序收到信号号 2,将会自动删除这两个文件 work1dataout

From the point in the shell program that this trap is executed, the two files work1 and dataout will be automatically removed if signal number 2 is received by the program.

因此,如果用户在此陷阱执行后中断程序的执行,你可以确保会清理这两个文件。紧随 rm 之后的 exit 命令是必需的,因为没有它,执行将在接收到信号时停止的位置继续进行。

Hence, if the user interrupts the execution of the program after this trap is executed, you can be assured that these two files will be cleaned up. The exit command that follows the rm is necessary because without it, the execution would continue in the program at the point that it left off when the signal was received.

信号号 1 为 hangup 生成。有人故意挂断电话线或电话线意外断开。

Signal number 1 is generated for hangup. Either someone intentionally hangs up the line or the line gets accidentally disconnected.

你可以通过向信号列表中添加信号号 1 来修改前面的 trap,以便在此情况下也删除两个指定的文件:

You can modify the preceding trap to also remove the two specified files in this case by adding signal number 1 to the list of signals −

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

现在,如果电话挂断或按下 Ctrl+C 键,这些文件将被删除。

Now these files will be removed if the line gets hung up or if the Ctrl+C key gets pressed.

如果指定的陷阱命令包含不止一个命令,则必须用引号引起来。还要注意,shell 在执行 trap 命令和接收到其中一个列出的信号时扫描命令行。

The commands specified to trap must be enclosed in quotes, if they contain more than one command. Also note that the shell scans the command line at the time that the trap command gets executed and also when one of the listed signals is received.

因此,在前面的示例中, WORKDIR$$ 的值将在执行 trap 命令时进行替换。如果你希望在接收到信号 1 或 2 时执行此替换,可以将命令放在单引号中:

Thus, in the preceding example, the value of WORKDIR and $$ will be substituted at the time that the trap command is executed. If you wanted this substitution to occur at the time that either signal 1 or 2 was received, you can put the commands inside single quotes −

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

Ignoring Signals

如果为 trap 列出的命令为空,则在接收到指定信号时将忽略该信号。例如,命令:

If the command listed for trap is null, the specified signal will be ignored when received. For example, the command −

$ trap '' 2

这指定了要忽略中断信号。你在执行不想被中断的操作时可能希望忽略某些信号。你可以指定要忽略的多个信号,如下所示:

This specifies that the interrupt signal is to be ignored. You might want to ignore certain signals when performing an operation that you don’t want to be interrupted. You can specify multiple signals to be ignored as follows −

$ trap '' 1 2 3 15

请注意,必须指定第一个参数才能忽略信号,并且不等于写以下内容,后者有其自己的单独含义:

Note that the first argument must be specified for a signal to be ignored and is not equivalent to writing the following, which has a separate meaning of its own −

$ trap  2

如果你忽略信号,所有子 shell 也将忽略该信号。但是,如果你指定在接收到信号时执行某个操作,则所有子 shell 在接收到该信号时仍将执行默认操作。

If you ignore a signal, all subshells also ignore that signal. However, if you specify an action to be taken on the receipt of a signal, all subshells will still take the default action on receipt of that signal.

Resetting Traps

在你更改了在接收到信号时执行的默认操作之后,如果你只省略第一个参数,你可以使用 trap 再次将其更改回来;因此:

After you’ve changed the default action to be taken on receipt of a signal, you can change it back again with the trap if you simply omit the first argument; so −

$ trap 1 2

这将接收到信号 1 或 2 时要执行的动作重置为默认值。

This resets the action to be taken on the receipt of signals 1 or 2 back to the default.