第九章 Shell信号发送与捕捉
9.1 Linux信号类型
信号(Signal):信号是在软件层次上对中断机制的一种模拟,通过给一个进程发送信号,执行相应的处理函数。
进程可以通过三种方式来响应一个信号:
1)忽略信号,即对信号不做任何处理,其中有两个信号不能忽略:SIGKILL及SIGSTOP。
2)捕捉信号。
3)执行缺省操作,Linux对每种信号都规定了默认操作。
Linux究竟采用了哪几种具体的方式以响应信号呢?这取决于传递给相应系统的API接口。
Linux支持的信号有:
| 编号 | 信号名称 | 缺省动作 | 描述 |
|---|---|---|---|
| 1 | SIGHUP | 终止 | 终止进程,挂起 |
| 2 | SIGINT | 终止 | 键盘输入中断命令,一般是CTRL+C |
| 3 | SIGQUIT | CoreDump | 键盘输入退出命令,一般是CTRL+| |
| 4 | SIGILL | CoreDump | 非法指令 |
| 5 | SIGTRAP | CoreDump | trap指令发出,一般调试用 |
| 6 | SIGABRT | CoreDump | abort(3)发出的终止信号 |
| 7 | SIGBUS | CoreDump | 非法地址 |
| 8 | SIGFPE | CoreDump | 浮点数异常 |
| 9 | SIGKILL | 终止 | 立即停止进程,不能捕获,不能忽略 |
| 10 | SIGUSR1 | 终止 | 用户自定义信号1,像Nginx就支持USR1信号,用于重载配置,重新打开日志 |
| 11 | SIGSEGV | CoreDump | 无效内存引用 |
| 12 | SIGUSR2 | 终止 | 用户自定义信号2 |
| 13 | SIGPIPE | 终止 | 管道不能访问 |
| 14 | SIGALRM | 终止 | 时钟信号,alrm(2)发出的终止信号 |
| 15 | SIGTERM | 终止 | 终止信号,进程会先关闭正在运行的任务或打开的文件再终止,有时候有的进程在运行任务会忽略此信号。不能捕捉 |
| 16 | SIGSTKFLT | 终止 | 处理器栈错误 |
| 17 | SIGCHLD | 可忽略 | 子进程结束时,父进程收到的信号 |
| 18 | SIGCONT | 可忽略 | 让终止的进程继续执行 |
| 19 | SIGSTOP | 停止 | 停止进程,不能忽略,不能捕获 |
| 20 | SIGSTP | 停止 | 停止进程,一般是CTRL+Z |
| 21 | SIGTTIN | 停止 | 后台进程从终端读数据 |
| 22 | SIGTTOU | 停止 | 后台进程从终端写数据 |
| 23 | SIGURG | 可忽略 | 紧急数组是否到达socket |
| 24 | SIGXCPU | CoreDump | 超出CPU占用资源限制 |
| 25 | SIGXFSZ | CoreDump | 超出文件大小资源限制 |
| 26 | SIGVTALRM | 终止 | 虚拟时钟信号,类似于SIGALRM,但计算的是进程占用的时间 |
| 27 | SIGPROF | 终止 | 类似与SIGALRM,但计算的是进程占用CPU的时间 |
| 28 | SIGWINCH | 可忽略 | 窗口大小改变发出的信号 |
| 29 | SIGIO | 终止 | 文件描述符准备就绪,可以输入/输出操作了 |
| 30 | SIGPWR | 终止 | 电源失败 |
| 31 | SIGSYS | CoreDump | 非法系统调用 |
CoreDump(核心转储):当程序运行过程中异常退出时,内核把当前程序在内存状况存储在一个core文件中,以便调试。执行命令ulimit -c如果是0则没有开启,也不会生成core dump文件,可通过ulimit -c unlimited命令临时开启core dump功能,只对当前终端环境有效,如果想永久生效,可修改/etc/security/limites.conf文件,添加一行 “* soft core unlimited”
默认生成的core文件保存在可执行文件所在的目录下,文件名为core。如果想修改core文件保存路径,可通过修改内核参数:echo “/tmp/corefile-%e-%p-%t” > /proc/sys/kernel/core_pattern 则文件名格式为core-命名名-pid-时间戳
Linux支持两种信号:
一种是标准信号,编号1-31,称为非可靠信号(非实时),不支持队列,信号可能会丢失,比如发送多次相同的信号,进程只能收到一次,如果第一个信号没有处理完,第二个信号将会丢弃。
另一种称为扩展信号 编号31-640称为可靠信号(实时模式下支持支持支持队列机制下发多少个进程即可收到相应数量次数的信件
信号种类繁多 �我们要掌握几类关键信号即可 对对于红色标记的内容 我们只需要记录下来即可
发送信号一般有两种情况:
一种是内核检测到系统事件,比如键盘输入CTRL+C会发送SIGINT信号。
另一种是通过系统调用kill命令来向一个进程发送信号。
9.2 kill命令
kill命令发送信号给进程。
命令格式:kill [-s sigspec | -n signum | -sigspec] pid | jobspec …
kill -l [sigspec]
-s # 信号名称
-n # 信号编号
-l # 打印编号1-31信号名称
示例:
给一个进程发送终止信号:
kill -s SIGTERM pid
或
kill -n 15 pid
或
kill -15 pid
或
kill -TREM pid
9.3 trap命令
trap命令定义shell脚本在运行时根据接收的信号做相应的处理。
命令格式:trap [-lp] [[arg] signal_spec …]
-l # 打印编号1-64编号信号名称
arg # 捕获信号后执行的命令或者函数
signal_spec # 信号名或编号
一般捕捉信号后,做以下几个动作:
1)清除临时文件
2)忽略该信号
3)询问用户是否终止脚本执行
示例1:按CTRL+C不退出循环
#!/bin/bash
trap “” 2 # 不指定arg就不做任何操作,后面也可以写多个信号,以空格分隔
for i in {1…10}; do
echo $i
sleep 1
done
bash a.sh
1
2
3
^C4
5
6
^C7
8
9
10
示例2:循环打印数字,按CTRL+C退出,并打印退出提示
#!/bin/bash
trap “echo ‘exit…’;exit” 2
for i in {1…10}; do
echo $i
sleep 1
done
bash test.sh
1
2
3
^Cexit…
示例3:让用户选择是否终止循环
#!/bin/bash
trap “func” 2
func() {
read -p "Terminate the process? (Y/N): " input
if [ $input == “Y” ]; then
exit
fi
}
for i in {1…10}; do
echo $i
sleep 1
done
bash a.sh
1
2
3
^CTerminate the process? (Y/N): Y
bash a.sh
1
2
3
^CTerminate the process? (Y/N): N
4
5
6
…
