在 bash 4 中增加变量会触发 EXIT,但在 bash 3 中则不会

发布于 11-26 22:10 字数 1383 浏览 0 评论 0原文

考虑这个(示例性)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 中的变量吗?

Consider this (exemplary) bash script:

#!/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:

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:

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.

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.

bash --version on the Cygwin bash says:

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

On Debian, it is:

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情绪少女 2024-12-03 22:10:56

来自 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,导致整体表达式返回非零,从而触发
错误退出。

现在介绍两个不同 bash 版本之间的区别:此更改
(( 行为似乎发生在 4.0 和 4.1 之间。在 4.0 ((
显然没有触发 errexit。有关详细信息,请参阅此 新闻 文件。
您必须向下滚动到第 135 行左右。来自源头的变更日志
分布似乎证实了这一点。

如果您只想增加变量而不使用退出状态,
有多种方法可以做到这一点。也许其他人可以提供建议
哪个是最好的,但一些可能性是:

  • var="$((var+1))",可移植的 POSIX sh 方法
  • ((var++) ) || true,强制语句始终为零
    退出状态(仅限 bash)

From the bash4 manpage on Debian:

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

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.

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++)) || true, forcing the statement to always have a zero
    exit status (bash only)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文