千家信息网

shell脚本中如何进行信号的捕捉

发表于:2025-11-08 作者:千家信息网编辑
千家信息网最后更新 2025年11月08日,本篇文章给大家分享的是有关shell脚本中如何进行信号的捕捉,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。trap从字面意思看就是就是陷
千家信息网最后更新 2025年11月08日shell脚本中如何进行信号的捕捉

本篇文章给大家分享的是有关shell脚本中如何进行信号的捕捉,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

trap从字面意思看就是就是陷阱的意思但是在shell脚本中trap时专门捕捉kill -9,kill -15,CTRL+C等信号的。

1、查看所有可用的信号

trap -l或kill -l即可

[root@linux1 ~]# kill -l63) SIGRTMAX-1  64) SIGRTMAX    [root@linux1 ~]# trap -l 1) SIGHUP   2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP 6) SIGABRT  7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR111) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM......

2、常见的信号如下:

Signal     Value     Comment─────────────────────────────SIGHUP        1      终止进程,特别是终端退出时,此终端内的进程都将被终止SIGINT        2      中断进程,几乎等同于sigterm,会尽可能的释放执行clean-up,释放资源,保存状态等(CTRL+C)SIGQUIT       3      从键盘发出杀死(终止)进程的信号SIGKILL       9      强制杀死进程,该信号不可被捕捉和忽略,进程收到该信号后不会执行任何clean-up行为,所以资源不会释放,状态不会保存SIGTERM      15      杀死(终止)进程,几乎等同于sigint信号,会尽可能的释放执行clean-up,释放资源,保存状态等SIGSTOP      19      该信号是不可被捕捉和忽略的进程停止信息,收到信号后会进入stopped状态SIGTSTP      20      该信号是可被忽略的进程停止信号(CTRL+Z)

真正的信号名字不是SIGXXX,而是去除SIG后的单词,每个信号还有对应的代号

比如向PID为12345的进程发起1信号

kill -1 12345kill -HUB 12345kill -SIGHUB 12345

3、trap的选项

trap -l列出当前系统支持的信号列表,上面已经使用过,根kill -l一样

trap -p等价于trap,查看shell已经布置好的陷阱

可以看到shell默认有三个陷阱,表示忽略20,21,22信号

[root@linux1 ~]# traptrap -- '' SIGTSTPtrap -- '' SIGTTINtrap -- '' SIGTTOU

4、陷阱捕捉到信号后干嘛

  • 忽略信号

  • 捕捉到信号后做相应的处理。主要是清理一些脚本创建的临时文件,然后退出。

5、设置一个可以忽略CTRL+C和15信号的陷阱

CTRL信号对应的是SIGINT 15信号对应的是SIGTERM

[root@linux1 ~]# trap '' SIGINT SIGTERM[root@linux1 ~]# traptrap -- '' SIGINTtrap -- '' SIGTERMtrap -- '' SIGTSTPtrap -- '' SIGTTINtrap -- '' SIGTTOU

这样,当前shell就不能被kill -15杀死

6、设置一个陷阱,捕捉到-15信号时,就打印"我抓到你啦~"

[root@linux1 ~]# trap 'echo "我抓到你啦~"' TERM[root@linux1 ~]# traptrap -- '' SIGINTtrap -- 'echo "我抓到你啦~"' SIGTERMtrap -- '' SIGTSTPtrap -- '' SIGTTINtrap -- '' SIGTTOU

效果,当我对当前bash发起kill -15信号时就打印出来了

[root@linux1 ~]# echo $$8827[root@linux1 ~]# kill -15 8827我抓到你啦~[root@linux1 ~]# kill -15 8827我抓到你啦~[root@linux1 ~]# kill -15 8827我抓到你啦~

7、在脚本中设置一个能忽略CTRL+C和CTRL+Z信号的脚本

CTRL+C是2信号,即SIGINT

CTRL+Z是20信号,即SIGTSTP

脚本:

脚本沉睡10s,然后打印success,脚本忽略INT和TSTP信号

[root@linux1 ~]# cat trap.sh#!/bin/bashtrap '' SIGINT SIGTSTPsleep 10echo success

效果:

CTRL+C也不能阻止我睡觉

[root@linux1 ~]# bash trap.sh ^C^C^Z^Z^C^C^Z^Zccc^Z^Z^Z^C^C^Csuccess

8、布置一个当脚本被终端时能清理垃圾并立即退出脚本的陷阱

脚本如下:

[root@linux1 ~]# cat trap1.sh#!/bin/bashtrap 'echo trap handing...;rm -rf /tmp/$BASHPID;echo TEMP files cleaned;exit' SIGINT SIGTERM SIGQUIT SIGHUPmkdir -p /tmp/$$/touch /tmp/$$/{a..c}.txtsleep 10echo first sleep successsleep 10echo second sleep success

这样,脚本除了SIGKILL信号(kill -9),总能清理掉临时垃圾

效果

刚开始一直不能终止,后来执行了下trap发现前面shell自己设置了一个忽略CTRL+C的陷阱,退出shell重进即可

[root@linux1 ~]# bash trap1.sh ^Ctrap handing...TEMP files cleaned

9、陷阱的守护对象

陷阱的守护对象是shell进程本身,不会守护shell环境内的子进程。但如果是信号忽略型陷阱,则会守护整个shell进程组使其忽略给定信号。

[root@linux1 ~]# cat trap2.sh #!/bin/bashtrap 'echo trap_handle_time: $(date +"%F %T")' SIGINT SIGTERMecho time_start: $(date +"%F %T")sleep 10echo time_end1: $(date +"%F %T")sleep 10echo time_end2: $(date +"%F %T")#执行脚本后,新开终端使用kill -15杀死它[root@linux1 ~]# killall -s SIGTERM trap2.sh#查看输出情况[root@linux1 ~]# ./trap2.sh time_start: 2019-08-27 10:43:48trap_handle_time: 2019-08-27 10:43:58time_end1: 2019-08-27 10:43:58time_end2: 2019-08-27 10:44:08

可以发现,kill执行完后,屏幕没有立即打印trap_handle,而是等sleep 10运行完后才打印的。sleep进程都被忽略型trap守护了

只要是向shell进程发送的信号,都会等待当前正在运行的命令结束后才处理信号,然后继续脚本向下运行。(实际上,只有当shell脚本中正在执行的操作是信号安全的系统调用时,才会出现信号无法中断进程的情况,而在shell下的各种命令,我们是没法直接知道哪些命令中正在执行的系统调用是系统调用的)。

但sleep命令发起的sleep()调用,是一个信号安全的,所以上面脚本中执行sleep的过程中,信号不会直接中断它们的运行,而是等待它运行完之后再执行信号处理命令。

10、如果shell中针对某信号设置了陷阱,则该shell进程接收到该信号时,会等待其内正在运行的命令结束才开始处理陷阱

11、CTRL+C和SIGINT不是等价的。当某一时刻按下CTRL+C,它是在向整个当前运行的进程组发送SIGINT信号。对shell脚本来说,SIGINT不仅发送给shell脚本进程,还发送给脚本中当前正在运行的进程

[root@linux1 ~]# cat trap2.sh #!/bin/bashtrap 'echo trap_handle_time: $(date +"%F %T")' SIGINT SIGTERMecho time_start: $(date +"%F %T")sleep 10echo time_end1: $(date +"%F %T")sleep 10echo time_end2: $(date +"%F %T")#执行脚本后,立马CTRL+C[root@linux1 ~]# bash trap2.sh time_start: 2019-08-27 10:20:53^Ctrap_handle_time: 2019-08-27 10:20:54time_end1: 2019-08-27 10:20:54time_end2: 2019-08-27 10:21:04

可以发现,CTRL+C后,不仅trap进行处理了,sleep也立马结束了;说明CTRL+C不仅让脚本进程收到了SIGINT信号,也让当前进程收到了SIGINT信号

以上就是shell脚本中如何进行信号的捕捉,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。

0