考虑这个(示例性)bash脚本:
#!/bin/bash -e
errorExit() {
echo "" >&2
echo "ERROR (${var_scriptfilename}):" >&2
echo "An unhandled error occurred." >&2
intentionalExit 1
}
intentionalExit () {
trap - EXIT # Unregister the EXIT trap
exit $1
}
trap errorExit EXIT # Trap script errors
var_scriptfilename="$(basename "$0")"
# ==== START OF TEST ====
var_counter=0
((var_counter++))
echo "var_counter is $var_counter" >&2
# ===== END OF TEST =====
intentionalExit 0
如果我在Cygwin的bash中运行它会产生预期的输出:
var_counter is 1
但是,如果我在我的Debian Squeeze盒子上运行它,这是它的预定目的地,我最终进入了EXIT陷阱:
ERROR (test.increment.sh):
An unhandled error occurred.
...这是为什么?
如果我删除了-e选项,它在两个系统上都按预期工作,但显然我想保持-e使用。
更加繁琐的“通用”变体var_counter=$(($var_counter+1))
可以在两个shell上设置-e,但是我更喜欢使用第一种表示法(或类似的东西),因为它在读取代码时显然是一个增量操作。
关于Cygwin bash的bash --version
说:
GNU bash, version 3.2.51(24)-release (i686-pc-cygwin)
Copyright (C) 2007 Free Software Foundation, Inc.
在Debian上,它是:
GNU bash, Version 4.1.5(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
我很感兴趣为什么会这样。有人知道这种行为的原因吗?
另外,是否有人知道在bash中增加变量的类似方法我可以使用?
来自Debian的bash4手册页:
((expression))
The expression is evaluated according to the rules described
below under ARITHMETIC EVALUATION. If the value of the expres‐
sion is non-zero, the return status is 0; otherwise the return
status is 1. This is exactly equivalent to let "expression".
并且 ...
-e Exit immediately if a pipeline (which may consist of a
single simple command), a subshell command enclosed in
parentheses, or one of the commands executed as part of
a command list enclosed by braces (see SHELL GRAMMAR
above) exits with a non-zero status.
所以正在发生的是((var++))
将var从0增加到1并返回0,导致整个表达式返回非零,从而触发errexit
。
现在,对于两个不同的bash版本之间的差异:((
行为的这种变化似乎发生在4.0和4.1之间。在4.0 ((
显然没有触发errexit。有关详细信息,请参阅此NEWS文件。你必须向下滚动到135行左右。源分发中的更改日志似乎证实了这一点。
如果您只想在不使用退出状态的情况下增加变量,则有多种方法可以执行此操作。也许其他人可以给出最好的建议,但有些可能性是:
var="$((var+1))"
,便携式POSIX sh
方法((var++)) || true
,强制声明始终具有零退出状态(仅限bash)