无论你的脚本是否成功运行,信号捕获都能让它平稳结束。
Shell 脚本的启动并不难被检测到,但 Shell 脚本的终止检测却并不容易,因为我们无法确定脚本会按照预期地正常结束,还是由于意外的错误导致失败。当脚本执行失败时,将正在处理的内容记录下来是非常有用的做法,但有时候这样做起来并不方便。而 Bash 中 trap
命令的存在正是为了解决这个问题,它可以捕获到脚本的终止信号,并以某种预设的方式作出应对。
响应失败
如果出现了一个错误,可能导致发生一连串错误。下面示例脚本中,首先在 /tmp
中创建一个临时目录,这样可以在临时目录中执行解包、文件处理等操作,然后再以另一种压缩格式进行打包:
-
#!/usr/bin/env bash
-
CWD=`pwd`
-
TMP=${TMP:-/tmp/tmpdir}
-
## create tmp dir
-
mkdir "${TMP}"
-
## extract files to tmp
-
tar xf "${1}" --directory "${TMP}"
-
## move to tmpdir and run commands
-
pushd "${TMP}"
-
for IMG in *.jpg; do
-
mogrify -verbose -flip -flop "${IMG}"
-
done
-
tar --create --file "${1%.*}".tar *.jpg
-
## move back to origin
-
popd
-
## bundle with bzip2
-
bzip2 --compress "${TMP}"/"${1%.*}".tar \
-
--stdout > "${1%.*}".tbz
-
## clean up
-
/usr/bin/rm -r /tmp/tmpdir
一般情况下,这个脚本都可以按照预期执行。但如果归档文件中的文件是 PNG 文件而不是期望的 JPEG 文件,脚本就会在中途失败,这时候另一个问题就出现了:最后一步删除临时目录的操作没有被正常执行。如果你手动把临时目录删掉,倒是不会造成什么影响,但是如果没有手动把临时目录删掉,在下一次执行这个脚本的时候,它必须处理一个现有的临时目录,里面充满了不可预知的剩余文件。
其中一个解决方案是在脚本开头增加一个预防性删除逻辑用来处理这种情况。但这种做法显得有些暴力,而我们更应该从结构上解决这个问题。使用 trap
是一个优雅的方法。
使用 trap 捕获信号
我们可以通过 trap
捕捉程序运行时的信号。如果你使用过 kill
或者 killall
命令,那你就已经使用过名为 SIGTERM
的信号了。除此以外,还可以执行 trap -l
或 trap --list
命令列出其它更多的信号:
-
$ trap --list
-
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