shell中trap的使用
- 格式:pdf
- 大小:98.13 KB
- 文档页数:3
shell中trap的使⽤
项⽬中的升级脚本可能耗时很长,在这段时间内,脚本没有任何输出的,这带给市场部署⼈员的感觉就是脚本好像卡住了。通常情况下,部
署⼈员都会直接CTRL+C停掉升级脚本,这会导致升级失败,最终需要开发⼈员介⼊去修复环境。
可以通过输出升级进度的⽅式提⽰部署⼈员升级正在进⾏中,但进度也可能在⼀段时间不动,⽽且⽆法避免意外终⽌升级的情况,此时可以
使⽤Shell的内建命令trap来忽略SIGINT这些信号,保证升级不会中断。
trap介绍
trap的格式如下,功能就是设置信号处理⾏为trap [-lp] [[arg] sigspec ...]
arg可以是shell命令或者⾃定义函数
sigspec可以是以下的⼀个或多个
定义在
1.
trap "echo 123" SIGINT
2.
trap "echo 123" INT
3.
trap "echo 123" 2
4.
trap "echo 123" int
5. trap "echo 123" Int
EXIT:在shell退出前执⾏trap设置的命令,也可以指定为0
RETURN:在函数返回时,或者.和source执⾏其他脚本返回时,执⾏trap设置的命令
DEBUG:在任何命令执⾏前执⾏trap设置的命令,但对于函数仅在函数的第⼀条命令前执⾏⼀次
1.
#!/bin/bash
2.
foo()
3.
{
4.
echo "foo 1"
5.
echo "foo 2"
6.
}
7.
8.
trap "echo 123" DEBUG
9.
foo
执⾏结果
1.
123 # 在函数前执⾏⼀次
2.
foo 1
3. foo 2
ERR:在命令结果为⾮0时,执⾏trap设置的命令
常⽤⽅式trap -l:列出所有信号的数值和名字,类似于kill -l
1.
[root@localhost ~]# trap -l
2.
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
3.
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
4.
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
5.
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
6.
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
7.
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
8.
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
9.
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
10.
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
11.
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
12.
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
13.
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
14. 63) SIGRTMAX-1 64) SIGRTMAX
trap -p:列出通过trap设置的信号处理命令。
1.
[root@localhost ~]# trap "echo INT" INT
2.
[root@localhost ~]# trap -p INT
3. trap -- 'echo INT' SIGINT
trap "" sigspec:忽略sigspec指定的信号
trap "do something" sigspec:收到sigspec指定的信号时,do some thing后,继续执⾏后续命令。
trap sigspec or trap - sigspec:恢复sigspec指定的信号的默认⾏为
trap的注意事项
trap可以在收到信号前的任意位置设置,并⾮需要在脚本的第⼀⾏,但是shell是按照顺序执⾏语句的,不会优先执⾏trap
1.
#!/bin/bash
2.
trap -p INT # 不输出任何信息
3. trap "echo get signal" INT
在函数中设置trap,也是全局⽣效的
1.
#!/bin/bash
2.
foo()
3.
{
4.
trap "echo get signal" INT
5.
}
6.
foo7.
trap -p INT # 输出trap -- 'echo get signal' SIGINT
对于同⼀个信号,只有最后⼀次trap⽣效trap只在本进程内有效,它的⼦进程不会继承trap的设置。
main.sh
1.
#!/bin/bash
2.
trap "get signal" INT
3.
./sub.sh
sub.sh
1.
#!/bin/bash
2.
trap -p INT # 没有任何信息
如果⼦进程阻塞着,当通过kill直接杀死⽗进程时,只有等到⼦进程退出,⽗进程才会处理信号。kill -2 杀掉以下脚本的进程,此时需
要等待10秒后,才会输出"get signal"。因为CTRL+C的信号是发送给进程组,此时sleep进程被INT信号中断了,所以⽴即输出了"getsignal",可以⽤Kill -2 发送信号到进程组达到⼀样的效果。
1.
#!/bin/bash
2.
trap "get signal" INT
3.
sleep 10
还有⼀个变通的⽅法就是把sleep放在后台进⾏,并⽤wait等待,wait是shell的内建命令,会被本进程收到的信号直接打断,此时sleep是继
续在后台执⾏的。
1.
#!/bin/bash
2.
trap "get signal" INT
3. sleep 10 & wait $!
处理SIGINT或者SIGQUIT时,需要特别注意。⽐如下⾯的脚本,CTRL+C后只是中断了⼀次sleep,当信号处理结束后,⼜会进⼊下
⼀次sleep,这可能并不符合预期。
1.
#!/bin/bash
2.
trap "echo get signal" INT
3.
sleep 10
4.
sleep 10
需要在处理信号中,将信号处理恢复到默认,并以INT信号再次杀掉⾃⼰
1.
#!/bin/bash
2.
trap "echo get signal;trap - INT;kill -s INT "$$" " INT
3.
sleep 10
4.
sleep 10参考资料