shell脚本进阶之信号的捕捉trap

shell脚本之信号的捕捉

​trap,翻译过来就是陷阱的意思,shell脚本中的陷阱是专门用来捕捉信号的。啥信号呢?比如经常使用的kill -9,kill -15,CTRL+C等都属于信号

1、查看所有可用的信号

trap -l或kill -l即可

[root@linux1 ~]# kill -l
63) 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) SIGUSR1
11) 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 12345
kill -HUB 12345
kill -SIGHUB 12345

3、trap的选项

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

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

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

[root@linux1 ~]# trap
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU

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

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

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

[root@linux1 ~]# trap '' SIGINT SIGTERM
[root@linux1 ~]# trap
trap -- '' SIGINT
trap -- '' SIGTERM
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU

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

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

[root@linux1 ~]# trap 'echo "我抓到你啦~"' TERM
[root@linux1 ~]# trap
trap -- '' SIGINT
trap -- 'echo "我抓到你啦~"' SIGTERM
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' 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/bash
trap '' SIGINT SIGTSTP
sleep 10
echo success

效果:

<font color=red>CTRL+C也不能阻止我睡觉</font>

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

success

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

脚本如下:

[root@linux1 ~]# cat trap1.sh
#!/bin/bash

trap 'echo trap handing...;rm -rf /tmp/$BASHPID;echo TEMP files cleaned;exit' SIGINT SIGTERM SIGQUIT SIGHUP
mkdir -p /tmp/$$/
touch /tmp/$$/{a..c}.txt
sleep 10
echo first sleep success
sleep 10
echo 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/bash
trap 'echo trap_handle_time: $(date +"%F %T")' SIGINT SIGTERM
echo time_start: $(date +"%F %T")
sleep 10
echo time_end1: $(date +"%F %T")
sleep 10
echo time_end2: $(date +"%F %T")

#执行脚本后,新开终端使用kill -15杀死它
[root@linux1 ~]# killall -s SIGTERM trap2.sh

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/11737.html