bash 中冷门但非常有用的命令: trap
trap 属于bash的内置命令,所以查看帮助用: help trap, 如果用”man trap“则会跳出bash的帮助文档;
trap命令的作用是:对捕获到的SIGNAL ,增加新的处理action; 而对于被捕获的SIGNAL原有的处理action不做变更;
A. 支持哪些信号呢? trap -l 可以列出所有支持的signal.
[root@www ~]# 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
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
[root@www ~]#
B. 如何使用trap来对特定信号添加额外的action ?
语法格式: trap COMMAND SIGNAL_DEFINATION
看下面的例子:
[root@www ~]# trap 'echo -e "\nCTRL_C PRESSED"' SIGINT
[root@www ~]# ^C #此处是同时按下: CTRL+C 的结果,并不是输入^C
CTRL_C PRESSED
[root@www ~]#
上面例子就是捕获CTRL+C, 当CTRL+C 按下的时候会产生SIGINT信号,trap捕获这个SIGINT信号,并执行 ‘echo -e "\nCTRL_C PRESSED"’这个命令,最终输出echo命令执行的结果, 同时对于原有的由CTRL+C引发的SIGINT的处理行为不做变更,上面的例子是:输出了^C, 同时执行了换行操作;
再看如下的一个例子:
[root@www ~]# trap 'echo -e "\nCTRL_C PRESSED"' SIGINT
[root@www ~]# sleep 1000
^C
[root@www ~]#
在这个例子中,当sleep的时候,按下了CTRL+C, 却没有成功捕获SIGINT 信号,为什么呢?
trap以及sleep运行的时候,各自分别产生了一个child process , 把trap对应的child process 记作A, sleep 对应的child process 记作为B. 而trap只是对其父进程起作用,而对父进程的子进程并不起作用,而B进程(sleep)属于A的父进程的子进程;所以trap命令无法对sleep命令的SIGINT起作用;
而如果把着两条命令放到一个脚本中,则会起作用,因为当运行脚本的时候, 按下ctrl+c触发的SIGINT信号被发送到了bash脚本对应的进程,而trap作为脚本中的一条命令,它本身是脚本的子进程,所以其父进程就是脚本进程;因此trap捕获到了SIGINT信号,此时trap捕获的是 发送给脚本的SIGINT信号,而不是发送给sleep的SIGINT信号;也就是说trap不可能捕获发送给sleep的任何信号;
[root@www ~]# cat test.sh
#!/bin/bash
trap "echo CTRL_C Pressed." SIGINT
sleep 100
[root@www ~]# bash -x test.sh
+ trap 'echo CTRL_C Pressed.' SIGINT
+ sleep 100
^C++ echo CTRL_C Pressed.
CTRL_C Pressed.
[root@www ~]#
C.
从上述介绍的trap可以捕获signal的范围来讲,trap的使用基本都是在 bash服务脚本中:
- 接受到特定信号的时候,用于kill 进程;比如:
trap "kill $THIS_PID" SIGTERM , 这样保证当脚本收到SIGTERM信号的时候,可以结束特定的服务进程; - 用于清理运行中的临时文件,比如: 如果用户按下了ctrl+c, 或者shell脚本收到了sigterm信号等,这时候可能有临时文件没有被移除,可以通过 trap来清理临时文件;
- 对于特定的SIGNAL, 可以返回指定的"exit code', 比如 下面的例子,如果按下ctrl+c, 那么$?的值为5.
#!/bin/bash
trap "exit 5" SIGINT
sleep 100
D.
关于trap命令的扩展:
1)显示特定SIGNAL的trap action:
[root@www ~]# trap -p SIGINT SIGTERM
trap -- 'echo 123' SIGINT
trap -- 'echo 123' SIGTERM
[root@www ~]#
2)取消trap action的设置:
[root@www ~]# trap SIGINT
[root@www ~]# trap SIGTERM
[root@www ~]# trap -p SIGINT SIGTERM
[root@www ~]#
本文原创,转载请著名出处