名称 值 描述
SIGHUP 1 控制终端发现被挂起或控制进程死亡
SIGINT 2 键盘终端
SIGQUIT 3 来自键盘的退出信号
SIGKILL 9 杀死进程的信号
SIGALRM 14 定时时钟中断
SIGTERM 15 终止信号
使用:kill -l 列出所支持的信号
发送信号:kill -signal pid
SIGTERM: kill pid等价于kill -s SIGTERM pid
如: kill -s SIGHUP 1001; 等价于 kill -1 1001,一个使用信号名称,一个使用代表该信号的整数
SIGKILL: SIGKILL有不能被捕捉的特殊能力,任何接受到它的进程都要立即终止,kill -9 1001
例子:
<span style="font-size:14px;">#keepalive.sh
#!/bin/bash
trap "rm -f ${TMPF}; exit 2" 1 2 3 15 #当脚本收到SIGHUP, SIGINT, SIGQUIT,SIGTERM时,临时文件会被删除
TMPF=".arch"
uname -m > "${TMPF}"
read ARCH < "${TMPF}"
rm -f "${TMPF}"
echo ${ARCH}
exit 0
--------------------------------------------------------------
#!/bin/bash
PROG="$1"
if [ "$PROG" = "" ]; then
echo "Usage: $0 cmd. "
exit 1
fi
Init()
{
if [ "$!" != "" -a "$!" != "0" ]; then
if kill -0 "$!" > /dev/null 2>&1; then
kill "$!" > /dev/null 2>&1 || return
fi
fi
$PROG &
}
CleanUp()
{
if [ "$!" != "" -a "$!" != "0" ]; then
kill -9 "$!" > /dev/null 2>&1
fi
exit 2
}
trap CleanUp 2 3 15
trap Init 1
while :
do
if [ "$!" != "" -a "$!" != "0" ]; then
wait "$!"
fi
$PROG &
done
exit 0
上面这个脚本启动由第一个参数指定的程序,并把它放到后台执行,然后等待这个程序结束
当这个程序结束时,脚本再次启动它,当接收到信号SIGINT,SIGQUIT,SIGTERM时,脚本
才退出,如果脚本接收到信号SIGUP,它将重新启动这个程序。
如:bash keepalive.sh ls
stty -a可以列出信号与键盘按键的对应关系,SIGINT为ctrl+c,SIGQUIT为ctrl+\
---------------------------------------------------------------------------------
shell定时器安装:
#!/bin/bash
PROG=$1
AlarmHandler()
{
echo "Got SIGALAM, cmd took too long"
KillSubProcs
exit 14
}
KillSubProcs()
{
kill ${CHPROCIDS:-$!}
if [ $? -eq 0 ];then
echo "Sub-processes killed."
fi
}
SetTimer()
{
DEF_TOUT=${1:-10};
if [ $DEF_TOUT -ne 0 ];then
sleep $DEF_TOUT && kill -s 14 $$ &
CHPROCIDS="$CHPROCIDS $!"
TIMERPROC=$!
fi
}
UnsetTimer()
{
echo "Start to unset timer"
kill $TIMERPROC
}
trap AlarmHandler 14
find / -name "1.txt" & #使用一个耗时间长的命令
SetTimer 15 #设置15秒
CHPROCIDS="$CHPROCIDS $!"
wait $!
sleep 40
UnsetTimer
echo "ALL Done."
exit 0
-------------------------------------------------------------</span>
一. trap捕捉到信号之后,可以有三种反应方式:
(1)执行一段程序来处理这一信号
(2)接受信号的默认操作
(3)忽视这一信号
二. trap对上面三种方式提供了三种基本形式:
第一种形式的trap命令在shell接收到signal list清单中数值相同的信号时,将执行双
引号中的命令串。
trap 'commands' signal-list
trap "commands" signal-list
为了恢复信号的默认操作,使用第二种形式的trap命令:
trap signal-list
第三种形式的trap命令允许忽视信号
trap " " signal-list
trap '' siganl-list
trap : signal-list
在关键操作中忽略信号:
trap '' 1 2 3 15
DoImportantStuff
trap 1 2 3 15
注意:
(1) 对信号11(段违例)不能捕捉,因为shell本身需要捕捉该信号去进行内存的转储。
(2) 在trap中可以定义对信号0的处理(实际上没有这个信号), shell程序在其终止(如
执行exit语句)时发出该信号。
(3) 在捕捉到signal-list中指定的信号并执行完相应的命令之后, 如果这些命令没有
将shell程序终止的话,shell程序将继续执行收到信号时所执行的命令后面的命令,这样将
很容易导致shell程序无法终止。
另外,在trap语句中,单引号和双引号是不同的,当shell程序第一次碰到trap语句时,
将把commands中的命令扫描一遍。此时若commands是用单引号括起来的话,那么shell不会
对commands中的变量和命令进行替换, 否则commands中的变量和命令将用当时具体的值来
kill -l可以列出系统的信号
通常我们需要忽略的信号有四个,即:HUP, INT, QUIT, TSTP,也就是信号1, 2, 3, 24
使用这样的语句可以使这些中断信号被忽略:
trap "" 1 2 3 24 或 trap "" HUP INT QUIT TSTP
用 trap :1 2 3 24 或 trap HUP INT QUIT TSTP使其回复默认值。
用stty -a可以列出中断信号与键盘的对应,分别执行上面的命令后,运行
tail -f /etc/passwd, 然后尝试用键盘中断,试试两种情况(默认和忽略)下有何不同。
更方便的是我们可以用在shell中用trap定义我们自己的信号处理程序
<span style="font-size:14px;">#!/bin/bash
#scriptname: trapping
#can use the singnal numbers of bash abbreviations seen
#below. Cannot use SIGINT ,SIGOUIT ,etc
trap 'echo Control-c will not terminate $0. ' INT
trap 'echo Control-\ will not terminate $0. ' QUIT
trap 'echo Control-Z will not terminate $0. ' TSTP
echo "Enter any string after the prompt. When you are ready to exit ,type \"stop\"."
while :
do
echo -n "Go ahead ...>"
read reply
if [[ $reply == [sS]top ]]; then
break
fi
done</span>
ref: http://www.cppblog.com/prayer/archive/2010/03/28/110743.html
NOTE:trap 对同种signal只能相应一种设定,如果在一个shell里面设置多个trap,如:
trap ' echo “aaaaaaaaaaa” ' INT
trap ' echo “bbbbbbbbbbb” ' INT那么它只会响应最后一个信号设定。
3. 信号究竟是在什么时候被 trap 处理?
这是本文最重要的一点。信号到底是什么时候被处理的?更准确地说,比如脚本正在执行某个命令时收到了某个信号,那么它会被立即处理,还是要等待当前命令完成?
我不打算直接说明答案。为了让我们对这个问题有更透彻的理解,让我们来做一下实验。看下面这个时常被用来讲解 trap 的脚本:
1 2 3 |
#!/bin/bash trap 'echo "INTERRUPTED!"; exit' INT sleep 100 |
大多数教程都是这么做的,运行这个脚本,按下 CTRL-C 。你看到了什么?脚本打出了“INTERRUPTED!”并停止了运行。这看起来似乎很正常、很直觉——以此看来, trap 会立即捕捉到信号并执行,不管当前正在执行的命令。许多脚本也正是在这个假设下写的。
然而真的是这样么?让我们做另一个实验——在一个终端执行这个脚本,并打开另一个终端,用ps-ef|grepbash
找到这个脚本的进程号,然后用kill-SIGINT pid
向这个进程发送 SIGINT 信号。你在原先的终端中看到了什么?没有任何反应!如果你愿意等上100秒,你最终会看到“INTERRUPTED!”被输出。这样看来 trap 是等到当前命令结束以后再处理信号。
这样的矛盾究竟是为什么?问题其实出在 CTRL-C 身上。 Bash 等终端的默认行为是这样的:当按下 CTRL-C 之后,它会向当前的整个进程组发出 SIGINT 信号。而 sleep 是由当前脚本调用的,是这个脚本的子进程,默认是在同一个进程组的,所以也会收到 SIGINT 并停止执行,返回主进程以后 trap 捕捉到了信号。
这篇文档给了我们一个更准确的说明——如果当前正有一个外部命令在前台执行,那么 trap 会等待当前命令结束以后再处理信号队列中的信号。(而许多教程出错的另一个原因就是——某些 shell 中 sleep 是内建命令,会被打断。)
那么上文的例子应当要如何写才能达到想要的效果呢?有两种方法:一、把 sleep 放到后台进行,再用内建的 wait 去等待其执行结束(详见上一段提到的那篇文档);二、暴力一点,把一长段 sleep 拆成一秒的小 sleep 的循环,这在对精度要求不高的情况下也是一个可行的办法(这应该不用写范例了吧?)。
ref: http://blog.youkuaiyun.com/elbort/article/details/8525599