Bash set -e и я = 0; пусть я ++ не согласен

следующий script с опцией отладки "set -e -v" сбой при операции инкремента только тогда, когда переменная имеет предыдущее значение нуля.

#!/bin/bash
set -e -v
i=1; let i++; echo "I am still here"
i=0; let i++; echo "I am still here"

i=0; ((i++)); echo "I am still here"

bash (GNU bash, версия 4.0.33 (1) -release (x86_64-apple-darwin10), но также GNU bash, версия 4.2.4 (1) -release (x86_64-unknown-linux -gnu))

любые идеи?

Ответ 1

ответ на мой вопрос заключается не в том, чтобы использовать let (или shift, или...), а для использования

i=$((i+1))

при попытке проверить bash script, установив < выход на ненулевой код состояния "с помощью

set -e

В руководстве bash указано, что set -e имеет эффект " Exit немедленно, если простая команда выходит с ненулевым статусом.".

К сожалению, пусть (и shift и...) возвращает результат вычисления (' Если последний аргумент arg равен 0, пусть возвращает 1; 0 в противном случае'). Поэтому вместо кода состояния получается какое-то возвращаемое значение. И иногда это возвращаемое значение будет равно нулю, а иногда и в зависимости от вычисления. Поэтому set -e вызовет выход script в зависимости от результата вашего вычисления!!! и нечего делать с этим, если вы не используете его никогда или не прибегаете к

let i++ || true

как указано arnaud576875, которое btw добавляет дополнительную нагрузку на процессор.

Использование

let ++i

работает только для конкретного случая, когда я не является -1, как с let я ++, который работает только тогда, когда я не равен 0. Поэтому полурешения.

Я люблю Unix, хотя у меня не было бы другого пути.

Ответ 2

Если последний аргумент let оценивается как 0, пусть возвращает 1 (так, ненулевой статус):

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

   let arg [arg ...]

Каждый аргумент - это арифметическое выражение для оценки. Если последний аргумент arg равен 0, пусть возвращает 1; 0. В противном случае возвращается 0.

i++ оценивается до нуля, когда i равно 0 (потому что это пост-инкремент, поэтому возвращается предыдущее значение i), поэтому let возвращает 1 и из-за set -e, bash существует.

Вот несколько решений:

let ++i         # pre-increment, if you expect `i` to never be -1
let i++ 1       # add an expression evaluating to non-zero
let i++ || true # call true if let returns non-zero

Ответ 3

Глядя на BASH manpage на set -e:

Выйдите немедленно, если простая команда (см. SHELL GRAMMAR выше) выходит с ненулевым статусом. [...]

Итак, если какой-либо оператор возвращает ненулевой код выхода, оболочка выйдет.

Взглянув на BASH manpage, в команде let:

Если последний аргумент arg равен 0, пусть возвращает 1; 0. В противном случае возвращается 0.

Но подождите! Ответ на i++ является одним, а не нулем! Это должно сработать!

Опять же, ответ с помощью BASH manpage на операторе инкремента:

id ++ id--: переменная post-increment и post-декремент

Хорошо, не так понятно. Попробуйте эту оболочку script:

#!/bin/bash
set -e -v
i=1; let ++i; echo "I am still here"
i=0; let ++i; echo "I am still here"

i=0; ((++i)); echo "I am still here"

Hmmm... работает так, как ожидалось, и все, что я делал, это изменение i++ до ++i в каждой строке.

i++ - оператор пост-инкремента. Это означает, что он увеличивает i после оператор let возвращает значение. Поскольку i был равен нулю перед тем, как приращиваться, оператор let возвращает ненулевое значение.

Тем не менее, ++i является оператором pre-increment. Это означает, что он увеличивает i перед возвратом статуса выхода. Поскольку i увеличивается до a 1, статус выхода становится равным нулю.

Надеюсь, это имеет смысл.