首页 > 学院 > 开发设计 > 正文

第12章 处理信号

2019-11-08 18:22:01
字体:
来源:转载
供稿:网友

信号就像一个软中断,当有一些重要的事情发生时,它们就会被发送到程序中。

本章要学习的知识点:

(1)在系统中如何表达信号;

(2)如何查看系统中所有的信号名和对应的数字;

(3)shell编程中常用到哪些信号;

(4)如何发送特定的信号;

(5)如何处理收到的信号;

(6)如何忽略某些信号及如何恢复它们;

(7)如何在脚本退出时做某些特定的处理;

1.     如何表达信号

信号实际上就是一个进程发送给另一个进程的消息,实现进程互通。

 现在linux系统中有几十种信号的类型,每一个信号都被分配了一个数字和一个名字。在使用时,既可以用数字,也可以用名字。在shell命令行中,可以通过trap-l或kill -l来查看系统中所有的信号。

 通过使用bash的内建命令kill可以发送任意指定的信号到某个进程。如果没有指定参数,kill命令默认发送信号15SIGTERM,在接收这个信号后,进程会终止执行。

    kill命令的格式如下:

       Kill [ -s sigspec | -n signum | -sigspec ] [pid | jobspec ]…

 通过sigspec或signum指定要发送的信号,sigspec既可以是任意大小写的信号名(有无SIG前缀都可以),也可以是给信号分配的数字,而signum只能是数字。kill命令会把指定的信号发送给进程号为pid的进程,或者发送给作业号为jobspec的进程。

 重要提示:

     (1)Ctrl+C等组合键只能给在当前终端中运行的前台进程发送信号,对于其他终端的进程或后台进程是不能发送信号的。

     (2)有时通过kill命令发送信号给某些进程需要root权限,接收进程才会执行希望的操作,此时要通过sudo命令执行kill发送信号。

2.     如何处理信号

在执行过程中,当用户按下组合键Ctrl+C或者使用kill命令发送TERM信号终止脚本的运行,那么临时文件就不会删除,这些残留文件会占用大量的硬盘空间,同时会给用户带来困扰。

 我们可以让运行的脚本在接收TERM信号时,自动地删除这些临时文件,因此需要实现一个自定义回归函数来执行这些操作,而注册TERM信号的这个回调函数就要通过trap命令来实现。

    trap的格式如下:

    trap cmd signa1 signal2…

其中,cmd可以是一系列命令或一个函数的名字,在它后面是一系列信号的数字或信号名。若cmd参数没有指定,shell脚本在接收到这些信号时会执行它们的默认行为。

案例1 实现以上功能的代码如下:

#!/bin/bash#使用当前脚本运行的进程PID创建一个唯一的文件TMPFILE=tmpfile.$$#定义收到信号时回调函数CleanUp(){if[ -f "$TMPFILE" ]then   echo   echo "Cleaning Up..."   #清除脚本产生的临时文件   rm -f $TMPFILE 2 > /dev/null   echo "Done."   echofi#结束脚本程序的执行exit 2}#注册新号回调函数CleanUptrap CleanUp 1 2 3 15#创建临时文件echoecho "Creating temporary file $TMPFILE ..."echo 'date' > $TMPFILEecho#模拟一些工作echo "Script is running ..."echo -n "       "#打印进度条TIME=15until [ "$TIME" -eq 0 ]doecho -n "###"#每打印一次#号就睡眠一秒sleep 1#让TIME的值减一,最终等于零时循环结束let TIME-=1done#执行到这里时,会清除临时文件echoecho "Cleaning Up termporary file $TIMPFILE ..."rm -f $TMPFILE 2 > /dev/nullechoexit 0

案例2 在案例1是多个信号共用一个信号处理函数,若希望为信号HUP实现一个单独的处理函数,用来重现初始化脚本,该如何实现?

#!/bin/bash#使用当前脚本运行的进程PID创建一个唯一的文件TMPFILE=tmpfile.$$#定义回调函数Init(){echoecho "Receive SIGHUP,Reinitialize script..."echo "Deleting temporary file,Creating new one..."rm -f $TMPFILE 2 > /dev/nullecho 'date' > $TMPFILEecho "Done."echo -n "     "TIME=15}#定义收到信号时回调函数CleanUp(){if[ -f "$TMPFILE" ]then   echo   echo "Cleaning Up..."   #清除脚本产生的临时文件   rm -f $TMPFILE 2 > /dev/null   echo "Done."   echofi#结束脚本程序的执行exit 2}#注册新号回调函数CleanUptrap CleanUp 2 3 15#为信号1注册回调函数Inittrap Init 1#创建临时文件echoecho "Creating temporary file $TMPFILE ..."echo 'date' > $TMPFILEecho#模拟一些工作echo "Script is running ..."echo -n "       "#打印进度条TIME=15until [ "$TIME" -eq 0 ]doecho -n "###"#每打印一次#号就睡眠一秒sleep 1#让TIME的值减一,最终等于零时循环结束let TIME-=1done#执行到这里时,会清除临时文件echoecho "Cleaning Up termporary file $TIMPFILE ..."rm -f $TMPFILE 2 > /dev/nullechoexit 0

案例3 是否可以在Shell脚本退出时,得到一个信号,从而处理某些特定的操作?

#!/bin/bash#这个回调函数会在脚本退出以前被调用quit_handler(){echoecho "In quit_handler():"echo "Script will exit."echo "Bye"echo}#注册伪信号0点回调函数,使得在脚本退出以前可以做一些事情,使用EXIT和0的效果是一样的trap quit_handler 0echo "These lines PRints before the /"trap/"--"echo "Even thought the Script see the /"trap/" first."echo#即使注释exit命令,伪信号0也会产生exit 0

3.     忽略信号

当执行一个需要较长时间才能完成的脚本时,用户可以通过组合键Ctrl+C来终止脚本的执行,但是如果用户的脚本在执行一些关键性的操作,不希望被打断,如备份或恢复瓷盘数据,就需要屏蔽用户使用Ctrl+C组合键或使用kill命令发送的INT(interrupt)信号。

解决方案:只要把trap命令中的操作指定为空,就可以替换默认的退出操作,从而忽略INT信号。

#使用空字符串货冒号屏蔽信号2 SIGINT

trap ‘’ INT

#冒号是bash的一个内建命令,它总是什么都不做并且总是返回0。

4.     定时器

案例1

如果希望用户在指定的时间内输入用户名,否则脚本就退出执行,该如何实现?

#!/bin/bash#定义函数Expire_Handler用来捕捉SIGALARM信号Expire_Handler(){echo echo "Got SIGALARM signal,Waiting for Your info too long!"echo "Bye."#从脚本中以退出代码14退出,用来表示接收到SIGALRM信号exit 14}#定义函数,用来设置一个定时器Start_Timer(){#如果没有指定参数,默认为10秒local INTERVAL=${1:-10}#检查参数大于0if [ $INTERVAL -gt 0 ]then   #15秒以后发送信号SIGALRM到脚本进程本身   sleep $INTERVAL && kill -s 14 $$ &   #记住后台进程PID,用来杀死定时器   #如果用户在最后期限以前输入信息   TIMERPID=$!else echo "Error:Interval must be positive integer!"exit 1fi}#定义函数,用来杀死后台进程,从而去除定时器Unset_Timer(){#首先杀死子进程kill 'pgrep -P $TIMERPID'#然后杀死父进程kill $TIMERPID}#设置定时器回调函数Expire_Handler来捕捉SIGALARM信号trap Expire_Handler 14echo echo "You have only 15 seconds to enter your info!"echo#把定时器设置为15秒到时间Start_Timer 15read -p "Please Enter your ID:" ID#如果用户在最后期限以前输入了信息,则移除定时器Unset_Timerechoecho "Your ID is: $id"echo "All Done."echoexit 0

5.     小结

信号也是进程间通信的一种方式,通过信号可以告诉程序某一个重要的时间正在发生。在脚本的执行过程中,由于信号可以在任何时候到达,会给原来的脚本增加一些相应的复杂性,所以在脚本中需要考虑可能接收到的信号,并添加处理这些信号的方法。

本章介绍了有关信号的内容,包括信号的概念,Shell编程中一些经常用到的信号,如何获得当前平台所支持的信号,发送信号和处理信号的方法,以及一些信号的应用。

本章的重要知识点包括:

(1)信号的两种表达方式,数字和名字;

(2)如何查看所有的信号名和对应的数字;

(3)发送信号的方法;

(4)如何定义信号处理的函数;

(5)进程在收到一个信号时的三种处理信号的方式;

(6)忽略信号和重置信号处理函数的方法;

(7)信号的一些常用应用,如删除临时文件和设置定时器。


上一篇:PAT 1046

下一篇:第11章 其他常用工具

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表