捕捉进程信号
信号是一种进程间的通信机制,它给应用程序提供一种异步的软件中断,是应用程序有机会接受其他程序活终端发送的命令(即信号).应用程序收到信号后,有三种处理方式:忽略,默认,捕捉.该进程收到一个信号后,会检查对该信号的处理机制.如果是SIG_IGN,就会忽略该信号;如果是SIG_DFT,则会采用系统默认的处理动作,通常是终止进程或忽略该信号;如果给该信号指定了一个处理函数(捕捉),则会中断当前进程正在执行的任务,转而去执行该信号的处理函数,返回后在继续执行被中断的任务.
在有些情况下,我们不希望自己的shell脚本在运行时刻被中断,比如说我们写的shell脚本设为某一用户的默认shell,使这一用户进入系统后只能做某一项工作,如数据库备份,我们可不希望用户使用Ctrl+C键便能进入到shell状态,做我们不希望看到的事情,这便用到了信号处理.
以下是一些常见的信号:
信号名称 |
信号数 |
说明 |
SIGHUP |
1 |
本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联。 登录Linux时,系统会分配给登录用户一个终端(Session)。在这个终端运行的所有程序,包括前台进程组和后台进程组,一般都属于这个Session。当用户退出Linux登录时,前台进程组和后台有对终端输出的进程将会收到SIGHUP信号。这个信号的默认操作为终止进程,因此前台进程组和后台有终端输出的进程就会中止。对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。 |
SIGINT |
2 |
程序终止(interrupt)信号,在用户键入INTR字符(通常是Ctrl+C)时发出 |
SIGQUIT |
3 |
和SIGINT类似, 但由QUIT字符(通常是Ctrl /)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。 |
SIGFPE |
8 |
在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。 |
SIGKILL |
9 |
用来立即结束程序的运行. 本信号不能被阻塞, 处理和忽略。 |
SIGALRM |
14 |
时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号 |
SIGTERM |
15 |
程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理. 通常用来要求程序自己正常退出. shell命令kill缺省产生这个信号。 |
捕获信号
当按下了Ctrl+C键或break键在终端一个shell程序的执行过程中,正常程序将立即终止,并返回命令提示符.这可能并使总是可取的,例如,你可能最终留下了一堆临时文件,将不会清理.
捕获这些信号是很容易的,trap命令的语法如下:
#trap commands signals
这里的commands可以是任何有效的linux命令,或一个用户定义的函数,信号可以是任意数量的信号,你想来捕获的列表.
一. trap捕捉到信号之后,可以有三种反应方式:
(1)执行一段程序来处理这一信号
(2)接受信号的默认操作
(3)忽视这一信号
二. trap对上面三种方式提供了三种基本形式:
第一种形式的trap命令在shell接收到signal list清单中数值相同的信号时,将执行双
引号中的命令串。
trap 'commands' signal-list
trap "commands" signal-list
为了恢复信号的默认操作,使用第二种形式的trap命令:
trap signal-list
第三种形式的trap命令允许忽视信号
trap " " signal-list
注意:
(1) 对信号11(段违例)不能捕捉,因为shell本身需要捕捉该信号去进行内存的转储。
(2) 在trap中可以定义对信号0的处理(实际上没有这个信号), shell程序在其终止(如执行exit语句)时发出该信号。
(3) 在捕捉到signal-list中指定的信号并执行完相应的命令之后, 如果这些命令没有将shell程序终止的话,shell程序将继续执行收到信号时所执行的命令后面的命令,这样将很容易导致shell程序无法终止。另外,在trap语句中,单引号和双引号是不同的,当shell程序第一次碰到trap语句时,将把commands中的命令扫描一遍。此时若commands是用单引号括起来的话,那么shell不会对commands中的变量和命令进行替换, 否则commands中的变量和命令将用当时具体的值来替换.
trap命令用于指定在接收到信号后将要采取的动作.常见的用途是在脚本程序被中断时完成清理工作.
测试案例:
按照用户的要求,我们需要屏蔽的是HUP INT QUIT TSTP几个信号.所以,可以运行:
#trap “”HUP INT QUIT TSTP
这个时候,可以试试打开一个持续的命令,然后中断其运行,例如:
#tail -f /var/log/messages
接着,试试用Ctrl+C或Ctrl+\来中断试试,该进程是不会退出的.
恢复信号
如果想恢复的话,可以用Ctrl+Z吧进程放到后台,然后运行:
#trap : HUP INT QUIT TSTP
然后,用#ps -ef看看其PID号,bg 1让程序继续运行,最后用kill杀掉即可.
其他
可以试试运行:
#trap “echo ‘hello world’” HUP INT QUIT TSTP
这样,当你运行Ctrl+C等中断时,会自动运行echo命令,结果就是实现helloworld字符串:
引用
#tail -f /var/log/messages
注意,这方式并不能屏蔽中断,按下Ctrl+C键仍然会退出程序,仅会再运行一个额外的命令而已.