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
, статус выхода становится равным нулю.
Надеюсь, это имеет смысл.