Действительно ли безопасно предположить, что пустой или переменные сброса будет заменен с нулем в арифметических выражениях удара?

На самом деле можно установить некоторые атрибуты на переменных с помощью declare (или старое typeset) встроенный. declare -i var1 var2 установит целочисленный атрибут на тех переменных. После этого присвоения, которые пытаются установить значения нецелого числа к тем переменным, повысят ошибку.

Но Ваша проблема с синтаксисом. При использовании значения переменной необходимо снабдить префиксом его имя $:

if [ "$var1" -lt "$var2" ]; then
    echo "$var1 is lt $var2"
else
    echo "$var2 is lt $var1"
fi

Исключениями являются арифметические оценки, где никакая потребность не для $:

if ((var1<var2)); then
    echo "$var1 is lt $var2"
else
    echo "$var2 is lt $var1"
fi

Как слово предупреждения, внутри [..] всегда двойная кавычка Ваши переменные для предотвращения расширения слова, портящего синтаксис выражения. (Я имею в виду, у Вас будут проблемы с переменными сброса, переменные, содержащие пустую строку и переменные, содержащие IFS символы.) Или можно использовать более новое и лучшее [[..]] вместо этого, который обрабатывает такие случаи правильно:

if [[ $var1 -lt $var2 ]]; then
    echo "$var1 is lt $var2"
else
    echo "$var2 is lt $var1"
fi
3
28.06.2013, 20:06
3 ответа

Из руководства:

Переменная оболочки, которая является пустой или сброс, оценивает к 0 при ссылке по имени, не используя синтаксис расширения параметра.

Я не знаю об этом изменявшемся, и это также имеет место в pdksh, ksh93, тире и zsh, но POSIX не указывает поведение.

Отметьте это если set -o nounset (иначе. set -u) в действительности, $((a)) или ((a+=1)) вызывает ошибку если a сброшен (в ударе и ksh93, но не в тире, pdksh или zsh).

Обратите внимание также, что это только применяется при использовании параметра непосредственно в арифметическом выражении $((a+1)), не, когда Вы используете замену параметра $(($a+1)). Контраст:

$ unset a
$ echo $((1 - a + 2))   # 1 - 0 + 2
3
$ echo $((a - $a + 2))  # 1 - (+2)
-1
2
27.01.2020, 21:13

Да, bash арифметическое расширение одолжено от ksh, и это было зарегистрированным путем в ksh с 80-х.

Отметьте однако, это в расширении арифметики POSIX как в $((x * 2)), поведение является неуказанным (POSIX) если $x содержит десятичную числовую константу (как в, 2 и -2 в порядке, но пустая строка или 1+1 не), что означает, что Вы не можете сделать то предположение в POSIX sh сценарии.

Также остерегайтесь (в bash, ksh, zsh по крайней мере):

$ echo $((2*$foo-2)) # actually $((2*-2))
-4
$ echo $((2*foo-2))  # actually $((2*0-2))
-2
3
27.01.2020, 21:13

Вероятно, безопасно предположить, что удар заменит пустыми переменными с 0 в любой довольно недавней системе.

Поскольку это документируется в страницу справочника для удара 4.2, это - конечно, зарегистрированное поведение, по крайней мере, с той версии. Как это описано как поведение тот путь (но недокументированное) в Усовершенствованном Руководстве по созданию сценариев Bash, можно ожидать, что поведение в любой версии удара было доступно, когда это было записано. Это, вероятно, возвращается к очень ранним версиям удара.

Если Вы захотите быть АБСОЛЮТНО строгими, однако, то необходимо будет проверить документацию на все версии удара, которые Вы хотите поддерживать, и Вы не можете сделать предположения ни об одной из тех версий, которые явно не документируют поведение.

Я не думаю, что необходимо быть абсолютно строгими, но если Вы не рискуете, можно использовать foo=${foo:-0} явно установить неопределенные переменные на 0 перед использованием их. Пример:

foo=1

foo=${foo:-0}
bar=${bar:-0}

echo "before math: foo=$foo, bar=$bar"
let 'foo += 2'
let 'bar += 2'
echo "after math: foo=$foo, bar=$bar"

Вывод:

before math: foo=1, bar=0
after math: foo=3, bar=2
2
27.01.2020, 21:13

Теги

Похожие вопросы