sh脚本和bash脚本
很容易检测到shell脚本何时启动,但是并不总是容易知道何时停止。 脚本可能会正常终止,就像作者希望的那样终止,但是由于意外的致命错误,脚本也可能会失败。 有时,保留脚本失败时正在进行的所有操作的残余是有益的,而其他时候则很不方便。 无论哪种方式,检测脚本的结尾并以某种预先计算的方式对其做出React都是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
关键字捕获执行期间可能发生的信号 。 如果您曾经使用过kill
或killall
命令(默认情况下调用SIGTERM
,则您已使用这些信号之一。 Shell还会响应许多其他信号,您可以使用trap -l
来查看其中的大多数信号(如“列表”中所示):
$
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
使用trap
可以预期这些信号中的任何一个。 除这些之外, trap
识别:
EXIT
:在shell进程本身退出时发生 ERR
:当命令(例如tar或mkdir )或内置命令(例如push或cd )以非零状态完成时发生 DEBUG
:表示调试模式的布尔值 要在Bash中设置陷阱,请使用trap
后跟要执行的命令列表,然后是触发它的信号列表。
例如,此陷阱检测到SIGINT
,即当用户在进程运行时按下Ctrl + C时发送的信号:
trap "{ echo 'Terminated with Ctrl+C'; }" SIGINT
带有临时目录问题的示例脚本可以通过检测SIGINT
,错误和成功退出的陷阱来修复:
#!/usr/bin/env bash
CWD =
`
pwd
`
TMP =
${TMP:-/tmp/tmpdir}
trap \
"{ /usr/bin/rm -r "
${TMP}
" ; exit 255; }" \
SIGINT SIGTERM ERR EXIT
## create tmp dir
mkdir
" ${TMP} "
tar xf
" ${1} "
--directory
" ${TMP} "
## move to tmp 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
## zip tar
bzip2
--compress
$TMP
/
" ${1%.*} " .tar \
--stdout
>
" ${1%.*} " .tbz
使用Bash函数 trap
语句。
陷阱对于确保脚本顺利结束(无论脚本是否成功运行)很有用。 完全依靠自动化垃圾收集永远是不安全的,因此一般来说,这是一个好习惯。 尝试在脚本中使用它们,看看它们能做什么!
翻译自: https://opensource.com/article/20/6/bash-trap
sh脚本和bash脚本