12.2. 陷阱

12.2.1. 概述

在某些情况下,您可能不希望脚本用户使用键盘中止序列过早退出,例如,因为必须提供输入或必须完成清理。trap 语句捕获这些序列,并且可以被编程为在捕获到这些信号时执行一系列命令。

trap 语句的语法非常简单

trap [命令] [信号]

这指示 trap 命令捕获列出的信号,信号可以是带有或不带有 SIG 前缀的信号名称,也可以是信号编号。如果信号为 0EXIT,则在 shell 退出时执行命令。如果信号之一是 DEBUG,则在每个简单命令之后执行命令列表。信号也可以指定为 ERR;在这种情况下,每次简单命令以非零状态退出时,都会执行命令。请注意,当非零退出状态来自 if 语句的一部分,或来自 whileuntil 循环时,这些命令将不会被执行。如果逻辑 AND (&&) 或 OR (||) 导致非零退出代码,或者当使用 ! 运算符反转命令的返回状态时,它们也不会被执行。

trap 命令本身的返回状态为零,除非遇到无效的信号规范。trap 命令接受一些选项,这些选项记录在 Bash info 页面中。

这是一个非常简单的例子,捕获用户输入的 Ctrl+C,之后会打印一条消息。当您尝试在不指定 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 命令依赖于一个数据库,该数据库定期使用以下命令构建makewhatis.cron使用 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