Как объявить и использовать логические переменные в shell-скрипте?
Я пытался объявить логическую переменную в скрипте оболочки, используя следующий синтаксис:
variable=$false
variable=$true
Правильный ли это способ? Также, если я хочу обновить эту переменную, нужно ли использовать тот же синтаксис? Наконец, правильный ли следующий синтаксис для использования логических переменных в выражениях?
if [ $variable ]
if [ !$variable ]
Спасибо за помощь!
5 ответ(ов)
Долгий рассказ коротко:
В Bash нет булевых значений
Команды true
и false
В Bash есть булевы выражения в терминах сравнения и условий. Однако то, что вы можете объявлять и с чем сравнивать в Bash, — это строки и числа. И на этом всё.
Где бы вы ни встретили true
или false
в Bash, это либо строка, либо команда/встроенная функция, используемая только для получения кода завершения.
Этот синтаксис...
if true; then ...
по сути аналогичен...
if COMMAND; then ...
где командой является true
. Условие истинно в том случае, если команда возвращает код завершения 0. true
и false
— это встроенные функции Bash, а иногда и отдельные программы, которые ничего не делают, кроме как возвращают соответствующий код завершения.
Условия в if..then..fi
При использовании квадратных скобок или команды test
вы полагаетесь на код завершения этой конструкции. Помните, что [ ]
и [[ ]]
— это тоже просто команды/встроенные функции, как и любые другие. Так что...
if [[ 1 == 1 ]]; then echo yes; fi
соответствует
if COMMAND; then echo yes; fi
где COMMAND
здесь — это [[
с параметрами 1 == 1 ]]
.
Конструкция if..then..fi
— это просто синтаксический сахар. Вы всегда можете просто выполнить команды, разделенные двойным амперсандом для того же эффекта:
[[ 1 == 1 ]] && echo yes
При использовании true
и false
в этих конструкциях тестирования вы на самом деле просто передаете строку "true"
или "false"
тестовой команде. Вот пример:
Верите или нет, но все эти условия дают один и тот же результат:
if [[ false ]]; then ...
if [[ "false" ]]; then ...
if [[ true ]]; then ...
if [[ "true" ]]; then ...
Кратко: всегда сравнивайте со строками или числами
Для ясности будущим читателям я бы рекомендовал всегда использовать кавычки вокруг true
и false
:
ДЕЛАЙТЕ
if [[ "${var}" == "true" ]]; then ...
if [[ "${var}" == "false" ]]; then ...
if [[ "${var}" == "yes" ]]; then ...
if [[ "${var}" == "USE_FEATURE_X" ]]; then ...
if [[ -n "${var:-}" ]]; then echo "var is not empty" ...
НЕ ДЕЛАЙТЕ
# Всегда используйте двойные квадратные скобки в bash!
if [ ... ]; then ...
# Это не так ясно и трудно ищется, как -n
if [[ "${var}" ]]; then ...
# Создает впечатление о булевых значениях
if [[ "${var}" != true ]]; then ...
# `-eq` предназначено для чисел и не так легко читается, как `==`
if [[ "${var}" -eq "true" ]]; then ...
Может быть
# Создает впечатление о булевых значениях.
# Может использоваться для строгой проверки опасных операций.
# Это условие ложно для всего, кроме буквальной строки "true".
if [[ "${var}" != "true" ]]; then ...
В вашем скрипте на Bash вы используете арифметические выражения для управления логикой выполнения. Вот перевод вашего скрипта на русский:
#!/bin/bash
false=0
true=1
((false)) && echo false
((true)) && echo true
((!false)) && echo not false
((!true)) && echo not true
Вывод:
true
not false
Объяснение:
- Вы задаёте переменные
false
иtrue
, гдеfalse
=0 (ложь) иtrue
=1 (истина). - С помощью арифметического выражения
((...))
вы проверяете значения переменных:((false))
возвращает 0 (ложь), поэтому команда не выполняется, и "false" не выводится.((true))
возвращает 1 (истина), поэтому "true" выводится.((!false))
(логическое отрицание) возвращает 1 (истина), так что "not false" выводится.((!true))
возвращает 0 (ложь), поэтому "not true" не выводится.
Таким образом, вы получаете в выводе только строки "true" и "not false".
Вместо того, чтобы имитировать булевое значение и оставлять "ловушку" для будущих читателей, почему бы не использовать более информативные значения, чем просто true и false?
Например:
build_state=success
if что-то-ужасное; then
build_state=failed
fi
if [[ "$build_state" == success ]]; then
echo "Иди домой, ты закончил"
else
echo "У тебя голова горит, бегай по кругу"
fi
Таким образом, вместо использования только двух состояний (успех/неудача) можно иметь различные значения, которые лучше отражают состояние вашей программы. Это делает код более читаемым и понятным для других разработчиков, которые будут с ним работать в будущем.
Для управления логикой с использованием булевых значений в Bash, вы можете воспользоваться следующим простым методом, как показано в примере:
# Тесты
var=
var=''
var=""
var=0
var=1
var="abc"
var=abc
if [[ -n "${var}" ]] ; then
echo 'true'
fi
if [[ -z "${var}" ]] ; then
echo 'false'
fi
# Результаты
# var= # false
# var='' # false
# var="" # false
# var=0 # true
# var=1 # true
# var="abc" # true
# var=abc # true
Если переменная никогда не объявлялась, результат будет: # false
.
Таким образом, простой способ установить переменную в значение "истина" (используя этот синтаксический метод) можно сделать, присвоив var=1
; в противном случае, чтобы установить ее в "ложь", можно использовать var=''
.
Справочная информация:
-n
= Истина, если длина строки переменной не равна нулю.
-z
= Истина, если длина строки переменной равна нулю.
Еще один способ использования булевых значений — это проверка пустоты значений. Это имеет преимущество в том, что тесты становятся короче:
first=1 # Истинное значение
second= # Ложное значение
[ -n "$first" ] && echo 'Переменная first истинна'
[ -z "$first" ] && echo 'Переменная first ложна'
[ -n "$second" ] && echo 'Переменная second истинна'
[ -z "$second" ] && echo 'Переменная second ложна'
Результат выполнения:
Переменная first истинна
Переменная second ложна
Вот альтернативный синтаксис тестирования в bash: [[ -n $one ]]
.
Как запросить ввод Yes/No/Cancel в скрипте оболочки Linux?
Как проверить, содержит ли строка подстроку в Bash
Как разобрать аргументы командной строки в Bash?
Как выводить команды оболочки по мере их выполнения
Разница между sh и Bash