在 C/C++ 中我们可以使用 signal()
函数为某个信号注册一个处理函数,这样当我们的程序收到给定信号时,就会自动执行我们指定的处理函数,这在某些时候非常有用。
那么我们能否在 shell 脚本中捕捉指定的信号,然后注册对应的处理函数呢?
当然是可以的,使用内置命令 trap
即可,用法非常简单,trap cmd_string signals...
。
cmd_string
是对应的“处理函数”,可以是任何有效的 shell 语句,建议使用单引号或双引号括起来;
signals
是要捕捉的信号名,如 INT
(用户按下 Ctrl+C)、TERM
(kill 的默认信号),多个信号用空格隔开;
可以有多个 trap 语句,只要它们捕捉的信号不冲突就行。当 shell 进程捕捉到对应信号后,会查找通过 trap 注册的处理语句,即cmd_string
,然后使用eval
解析并执行我们传递给它的cmd_string
。例子:
1
2
3
4
5
6
7
8
9
#!/bin/bash
trap 'echo +$0+; exit' INT
trap 'echo -$0-; exit' TERM
while true; do
echo 'hello, world'
sleep 1
done
添加可执行权限,然后执行脚本。
当我们按下 Ctrl+C 组合键,就会执行 echo +$0+; exit
,打印当前脚本名然后退出;
当我们使用 kill
给该 shell 进程发送 TERM 信号时,脚本就会执行 echo -$0-; exit
语句。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ chmod +x test.sh
$ ./test.sh
hello, world
hello, world
^C+./test.sh+
$ ./test.sh & { pid=$!; sleep 3; kill -TERM $pid; } && wait
[1] 13484
hello, world
hello, world
hello, world
-./test.sh-
[1]+ Done ./test.sh