【问题标题】:Incrementing a variable triggers EXIT in bash 4, but not in bash 3增加变量会在 bash 4 中触发 EXIT,但不会在 bash 3 中触发
【发布时间】:2011-10-16 03:52:49
【问题描述】:

考虑这个(示例)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,但我更喜欢使用第一个表示法(或类似的东西),因为它显然是一个增量读取代码时的操作。

bash --version 在 Cygwin bash 上说:

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 中的变量吗?

【问题讨论】:

  • 您在set -vx 时看到什么有用的信息吗?祝你好运。

标签: bash version exit increment


【解决方案1】:

来自 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)

【讨论】:

  • 非常感谢您,这肯定会为您提供很多信息。我想,看到 EXIT 只是因为我从 0 开始计数而被调用,我可以使用前增量而不是后增量,即 ((++var_counter)) 而不是 ((var_counter++))。然后计算结果从 1 开始,返回值将始终为零。我现在已经在提到的两个 shell 上成功地测试了它。
  • @FelipeAlvarez (( )) 是一个独立的命令,就像在其他编程语言中执行语句一样。 (( 2 + 2 )) 将运行,将 0 返回到 shell。 $(( )) 是一个扩展 - 表达式的结果被插入回命令行中以代替 $(( )) 表达式。它通常用作较长命令行的一部分。
猜你喜欢
  • 2020-12-28
  • 1970-01-01
  • 1970-01-01
  • 2012-12-19
  • 2021-02-01
  • 2020-06-23
  • 2023-03-29
  • 2020-02-12
  • 1970-01-01
相关资源
最近更新 更多