Увеличение переменной запускает выход в bash 4, но не в bash 3

рассмотрим этот (примерный) скрипт 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 
}
trap errorExit EXIT # Trap script errors
var_scriptfilename="$(basename "")"
# ==== START OF TEST ====
var_counter=0
((var_counter++))
echo "var_counter is $var_counter" >&2
# ===== END OF TEST =====
intentionalExit 0

если я запускаю его в bash в Cygwin, это производит предполагаемый выход:

var_counter is 1

однако, если я запускаю его на моем Debian Squeeze box, который является его назначением, я оказываюсь в ловушке выхода:

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

...Почему так?

если я удалю параметр-e, он работает так, как ожидалось в обеих системах, но я хочу сохранить-e в использовании, очевидно.

немного более громоздкий " универсальный" вариант var_counter=$(($var_counter+1)), работает с-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, которую я мог бы использовать?

1 ответов


из страницы bash4 в 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".

и еще ...

-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. Видеть это новости файл для деталей. Прокрутите вниз до строки 135 или около того. Изменений от источника распределение, кажется, подтверждает это.

если вы просто хотите, чтобы переменная увеличивалась без использования статуса выхода, есть несколько способов сделать это. Может быть, кто-то другой мог бы дать совет? на котором лучше всего, но некоторые возможности:

  • var="$((var+1))", портативный POSIX sh метод
  • ((var++)) || true, заставляя утверждение всегда иметь ноль статус выхода (только bash)