Увеличение переменной вызывает EXIT в 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 $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's bash, он выдает намеченный результат:
var_counter is 1
Тем не менее, если я запустил его на своем поле Debian Squeeze, которое является его предназначением, я попаду в ловушку EXIT:
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 ответ
С man-страницы 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++))
увеличивает переменную от 0 до 1 и возвращает 0, в результате чего общее выражение возвращает ненулевое значение, что вызывает errexit
,
Теперь о разнице между двумя разными версиями Bash: это изменение в ((
поведение, по-видимому, произошло между 4,0 и 4,1. В 4.0 ((
по-видимому, не вызывает errexit. Смотрите этот файл NEWS для деталей. Вам придется прокрутить вниз до строки 135 или около того. Список изменений из исходного дистрибутива, кажется, подтверждает это.
Если вы просто хотите, чтобы переменная увеличивалась без использования состояния выхода, есть несколько способов сделать это. Может быть, некоторые другие люди могут дать совет, какой из них лучше, но некоторые возможности:
var="$((var+1))"
Портативный POSIXsh
метод((var++)) || true
, заставляя оператор всегда иметь нулевой статус выхода (только bash)