简体   繁体   English

递增变量会触发bash 4中的EXIT,但不会触发bash 3中的EXIT

[英]Incrementing a variable triggers EXIT in bash 4, but not in bash 3

Consider this (exemplary) bash script: 考虑这个(示例性)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

If I run it in Cygwin's bash it produces the intended output: 如果我在Cygwin的bash中运行它会产生预期的输出:

var_counter is 1

However, if I run it on my Debian Squeeze box, which is its intended destination, I end up in the EXIT trap: 但是,如果我在我的Debian Squeeze盒子上运行它,这是它的预定目的地,我最终进入了EXIT陷阱:

ERROR (test.increment.sh):
An unhandled error occurred.

...Why is that? ...这是为什么?

If I remove the -e option it works as expected on both systems, but I want to keep -e in use, obviously. 如果我删除了-e选项,它在两个系统上都按预期工作,但显然我想保持-e使用。

The slightly more cumbersome "universal" variant, var_counter=$(($var_counter+1)) , works with -e being set on both shells, but I would prefer to use the first notation (or something similar-looking) since it clearly sticks out as an increment operation when reading the code. 稍微繁琐的“通用”变体var_counter=$(($var_counter+1)) ,在两个shell上都设置了-e,但我更喜欢使用第一个符号(或类似的东西),因为它清楚在阅读代码时伸出作为增量操作。

bash --version on the Cygwin bash says: bash --version在Cygwin bash上的bash --version说:

GNU bash, version 3.2.51(24)-release (i686-pc-cygwin)
Copyright (C) 2007 Free Software Foundation, Inc.

On Debian, it is: 在Debian上,它是:

GNU bash, Version 4.1.5(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.

I am intrigued as to why this is that way. 我很感兴趣为什么会这样。 Does anybody know the cause of this behavior? 有人知道这种行为的原因吗?

Also, does anybody know of a similar-looking way to increment a variable in bash that I could use? 另外,是否有人知道在bash中增加变量的类似方法我可以使用?

From the bash4 manpage on Debian: 来自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".

and also ... 并且 ...

-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.

So what is happening is ((var++)) increments var from 0 to 1 and returns 0, causing the overall expression to return non-zero, which triggers errexit . 所以正在发生的是((var++)) var从0增加到1并返回0,导致整个表达式返回非零,从而触发errexit

Now for the difference between the two different bash versions: this change in (( behavior seems to have occurred between 4.0 and 4.1. In 4.0 (( apparently did not trigger errexit. See this NEWS file for the details. You'll have to scroll down to line 135 or so. The Changelog from the source distribution seems to confirm this. 现在来看两个不同的bash版本之间的区别:这个改变((行为似乎发生在4.0和4.1之间。在4.0中((显然没有触发errexit。有关详细信息,请参阅此NEWS文件。你必须滚动从源代码发布的更改日志似乎证实了这一点。

If you just want a variable incremented without using the exit status, there's multiple ways to do it. 如果您只想在不使用退出状态的情况下增加变量,则有多种方法可以执行此操作。 Maybe some other people could give advice on which is the best, but some possibilities are: 也许其他人可以给出最好的建议,但有些可能性是:

  • var="$((var+1))" , the portable POSIX sh method var="$((var+1))" ,便携式POSIX sh方法
  • ((var++)) || true ((var++)) || true , forcing the statement to always have a zero exit status (bash only) ((var++)) || true ,强制语句始终具有零退出状态(仅限bash)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM