ITEEDU

12.2. 陷阱

12.2.1. 概要

可能有这样的情况,你不想使用你的脚本的用户不合时宜地通过键盘来结束进程,比如因为必须提供输入或者必须进行某些清理工作。 trap 语句捕获到这些序列且能够被编制出来在不活这些信号时候执行一系列的命令。

trap 语句的语法是这样的:

trap [COMMANDS] [SIGNALS]

意味着 trap 命令会捕捉在 SIGNALS 列出的可能带有或者没有 SIG 前缀的信号,或者信号数字。如果一个信号是 0 或者 EXIT,那么 COMMANDS 在shell退出时候执行。如果其中一个信号是 DEBUGCOMMANDS 列表在每个简单命令后执行。一个信号也可以指定为 ERR;这样的情况下 COMMANDS 在每次一个简单命令以非零状态退出时执行。注意这些命令不会在非零退出状态来自一个 if 语句时执行,或者来自一个 while 或者 until 循环。如果一个逻辑 AND (&&) 或者 OR (||) 出现在非零退出状态中,所有都不会执行,或者当一个命令的退出状态使用 ! 操作符进行取反。

除非遭遇一个非法的信号,否则 trap 命令的返回状态是0。trap 命令带一组选项,在Bash的info页面中有记录。

这里有个非常简单的例子,从用户处捕捉 Ctrl+C, upon which a message is printed. 当你尝试着不指定 KILL 信号来杀掉这个程序时,什么都不会发生:

#!/bin/bash
# traptest.sh

trap "echo Booh!" SIGINT SIGTERM
echo "pid is $$"

while :			# This is the same as "while true".
do
        sleep 60	# This script is not really doing anything.
done

12.2.2. Bash怎样解释陷阱

每当Bash收到一个预先设置等待命令完成的陷阱的信号,在命令结束之前,陷阱不会执行。当Bash通过内建的命令 wait 来等待一个异步的命令,陷阱已经发送的信号的接受会导致内建的 wait 立即在陷阱执行后返回一个大于128的推出状态。

12.2.3. 更多例子

12.2.3.1. 检测一个已经使用的变量

每当调试较长的脚本的时候,你可能想给于一个变量 trace 属性和陷阱的 DEBUG 信息。通常你会像这样 VARIABLE=value来给变量赋值。用下面的几行来代替变量的声明可能会为你脚本的行为提供非常有价值的信息:

declare -t VARIABLE=value

trap "echo VARIABLE is being used here." DEBUG

# rest of the script

12.2.3.2. 在退出的时候清理垃圾

whatis 命令依靠由cron执行 makewhatis.cron 生成的数据库:

#!/bin/bash

LOCKFILE=/var/lock/makewhatis.lock

# Previous makewhatis should execute successfully:

[ -f $LOCKFILE ] && exit 0

# Upon exit, remove lockfile.

trap "{ rm -f $LOCKFILE ; exit 255; }" EXIT

touch $LOCKFILE
makewhatis -u -w
exit 0