跳转到内容

Unix 指南/解释/信号

来自维基教科书,开放的书籍,开放的世界

信号是软件中断,通知进程某个条件或事件已经发生。产生信号的事件示例包括:

  • 进程尝试进行除零运算
  • 用户在终端按下中断键
  • 进程使用 kill 命令或 kill 函数向另一个进程发送信号

可以使用以下命令显示所有不同信号的列表:

$ kill -l

kill 命令还可以用于向其他进程发送信号。启动一个在后台运行 1000 秒的睡眠进程

$ sleep 1000 &
[1]     14936
$ ps
   PID TTY      TIME CMD
 14936 pts/7    0:00 sleep
 12203 pts/7    0:01 bash

注意,当你运行它时,进程 ID(很可能)会不同。下面的命令行向进程 14936(在本例中)发送 SIGKILL 信号

$ kill -KILL 14936
$ ps
   PID TTY      TIME CMD
 12203 pts/7    0:01 ksh
[1] + Killed                   sleep 1000 &

收到 SIGKILL 信号后,sleep 进程将终止。

进程可以以三种不同的方式响应信号

  • 执行默认操作
  • 忽略信号。
  • 执行指定函数(称为信号处理程序)

进程在收到信号时执行的默认操作取决于信号类型。大多数信号(如 SIGKILL)会导致进程终止。其他信号,如 SIGQUIT,会导致进程终止并生成核心转储

$ sleep 1000 &
[1]     14950
$ kill -QUIT 14950
$ ps
   PID TTY      TIME CMD
 12203 pts/7    0:01 bash
[1] + Quit(coredump)           sleep 1000 &
$ ls core
core

核心文件可能很大,因此请将其删除

$ rm core

可以使用 trap 命令捕获信号。在文件 catch_signal.sh 中创建以下 shell 脚本

#!/bin/bash
trap 'echo "GOTCHA!"' INT KILL
while :
do sleep 10
done

在后台运行 catch_signal.sh

$ catch_signal.sh &
[1]     15053
$ kill -INT 15053
$ GOTCHA!

信号已捕获,并且未终止(这是 SIGINT 的默认操作),而是将消息 "GOTCHA!" 回显到标准输出。

但是,某些信号无法捕获,例如 SIGKILL

$ kill -KILL 15053
[1] + Killed                   catch_signal &

运行 catch_signal.sh;在前景中

$ catch_signal

按下中断键(通常是 Ctrl+C)

^CGOTCHA!

现在按下退出键

^\catch_signal[3]: 15102 Quit(coredump)
$ ls core # will have generated a core file
core

使用 nohup 运行的命令在用户注销时不会终止。

在文件 dont_hangup.sh 中创建脚本,并使其可执行

#!/bin/bash

while :
do
    date
    sleep 100
done

在后台运行它,前面加上命令 nohup

$ nohup dont_hangup.sh &
[1]     15224
Sending output to nohup.out

检查其运行状态:id(在本例中为 12203)

$ ps -fu aholt
aholt 15224 12203 pts/7  sh ./dont_hangup.sh
aholt 15232 15224 pts/7  sleep 100

记录 "dont_hangup" 的父进程 ID(在本例中为 12203)和终端设备,然后注销你的会话。

再次登录。可以看到 dont_hangup.sh 仍在运行

$ ps -fu aholt
aholt 15224      1 ? 0:00 sh ./dont_hangup.sh
aholt 15237 15224  ? 0:00 sleep 100

虽然 "dont_hangup.sh" 仍在运行,但其父进程已更改。父进程的 ID 为 1(而不是之前的 12203),并且不再与终端设备关联。使用 nohup 等同于忽略 SIGHUP,即

trap '' HUP
华夏公益教科书