Я попытался объявить логическую переменную в сценарии оболочки, используя следующий синтаксис:
variable=$false
variable=$true
Это правильно? Кроме того, если бы я хотел обновить эту переменную, я бы использовал тот же синтаксис? Наконец, правильный ли следующий синтаксис для использования булевых переменных в качестве выражений?
if [ $variable ]
if [ !$variable ]
true
иfalse
в контексте большинство фрагментов ниже только простые строки, а не тоbash built-ins
!!! Пожалуйста, прочитайте ответ Майка Холта ниже. (Это один из примеров, когда высоко оцененный и принятый ответ ИМХО сбивает с толку и затеняет проницательный контент в менее проголосовавших ответах)true
. Оказывается, первоначальный ответ Мику действительно называлtrue
встроенным, но пересмотренный ответ - нет. Это привело к тому, что указанные комментарии оказались неверными в отношении того, как работает код Мику. С тех пор ответ Мику был отредактирован для явного отображения как исходного, так и пересмотренного кода. Надеемся, что это ставит в тупик путаницу раз и навсегда.[ true ] && echo yes, true is true
и (Upppsss)[ false ] && echo yes, false is also true
. / bin / true и / bin / false дают код возврата $? для функций не для сравнения.variable=something
она истинна, если не установленаvariable=
, будет ложно[[ $variable ]] && echo true || echo false
и наоборот[[ ! $variable ]] && echo false || echo true
Ответы:
Пересмотренный ответ (12 февраля 2014 г.)
Оригинальный ответ
Предостережения: https://stackoverflow.com/a/21210966/89391
От: Использование логических переменных в Bash
Причина, по которой первоначальный ответ включен сюда, заключается в том, что комментарии до пересмотра 12 февраля 2014 года относятся только к первоначальному ответу, и многие комментарии неверны, когда связаны с пересмотренным ответом. Например, комментарий Денниса Уильямсона о bash, встроенном
true
2 июня 2010 года, относится только к первоначальному ответу, а не к пересмотренному.источник
if
оператор выполняет содержимое переменной, которая является встроенной в Bashtrue
. Любая команда может быть установлена как значение переменной, и ее выходное значение будет оценено.&&
и||
:# t1=true; t2=true; f1=false;
#if $t1 || $f1; then echo is_true ; else echo is_false; fi;
(возвращает «true», поскольку t1 = true) #if $t1 && $f1 || $t2; then echo is_true ; else echo is_false; fi
(возвращает «true», так как t2 = true) . Опять же, это работает ТОЛЬКО потому, что «true» / «false» являются встроенными в bash (возвращая true / false). Вы не можете использовать «if $ var ...», если var не является cmd (то есть true или false)TL; DR
Проблемы с ( оригинальным ) ответом Мику
Я не рекомендую принятый ответ 1 . Его синтаксис хорош, но у него есть некоторые недостатки.
Скажем, у нас есть следующее условие.
В следующих случаях 2 это условие оценивается как истинное и выполняет вложенную команду.
Как правило, вы хотите, чтобы ваше условие оценивалось как true, когда ваша «логическая» переменная
var
в этом примере явно установлена в true. Все остальные случаи опасно вводят в заблуждение!Последний случай (# 5) особенно капризен, потому что он выполнит команду, содержащуюся в переменной (поэтому условие оценивается как истинное для допустимых команд 3, 4 ).
Вот безобидный пример:
Цитировать ваши переменные безопаснее, например
if "$var"; then
. В вышеуказанных случаях вы должны получить предупреждение о том, что команда не найдена. Но мы все еще можем сделать лучше (см. Мои рекомендации внизу).Также см. Объяснение Майка Холта о первоначальном ответе Мику.
Проблемы с ответом Hbar
Этот подход также имеет неожиданное поведение.
Можно ожидать, что вышеприведенное условие оценивается как ложное, поэтому никогда не выполняете вложенный оператор. Сюрприз!
Кавычка value (
"false"
), кавычка переменной ("$var"
), или использованиеtest
или[[
вместо[
, не имеют значения.То , что я действительно рекомендую:
Вот способы, которые я рекомендую вам проверить ваши "Booleans". Они работают как положено.
Они все в значительной степени эквивалентны. Вам нужно будет набрать на несколько клавиш больше, чем в других ответах 5 , но ваш код будет более защищенным.
Сноски
man woman
все равно будет считаться допустимой командой, даже если такой справочной страницы не существует.источник
==
с[
илиtest
не является переносимым. Учитывая переносимость является единственным преимуществом[
/test
имеет более[[
, придерживайтесь=
.Кажется, здесь есть некоторое недопонимание относительно встроенной функции Bash
true
, а более конкретно, о том, как Bash расширяет и интерпретирует выражения в квадратных скобках.Код в ответе miku не имеет ничего общего ни со встроенной системой Bash
true
,/bin/true
ни с каким-либо другим видомtrue
команды. В этом случаеtrue
это не что иное, как простая символьная строка, и никакой вызовtrue
команды / встроенной функции никогда не выполняется ни с помощью присваивания переменной, ни с помощью вычисления условного выражения.Следующий код функционально идентичен коду в ответе мику:
Только разница состоит в том , что четыре символа сравниваемых «у», «е», «а» и «ч» вместо «т», «г», «и», и «е». Вот и все. Не было предпринято никаких попыток вызвать команду или встроенный объект named
yeah
, а также (в примере miku) никакой особой обработки не происходит, когда Bash анализирует токенtrue
. Это просто строка, причем совершенно произвольная.Обновление (2014-02-19): после перехода по ссылке в ответе мику, теперь я вижу, откуда происходит некоторая путаница. В ответе Мику используются одиночные скобки, но фрагмент кода, на который он ссылается, не использует скобки. Это просто:
Оба фрагмента кода будут вести себя одинаково, но скобки полностью изменят то, что происходит под капотом.
Вот что Bash делает в каждом случае:
Без скобок:
$the_world_is_flat
до строки"true"
."true"
как команду.true
команду (встроенную или/bin/true
, в зависимости от версии Bash).true
команды (который всегда равен 0) с 0. Напомним, что в большинстве оболочек код выхода 0 указывает на успех, а все остальное указывает на сбой.if
заявлении , вthen
положениеСкобки:
$the_world_is_flat
до строки"true"
.string1 = string2
.=
Оператор в Bash сравнения строк оператора. Так..."true"
и"true"
.if
оператораthen
.Код без скобок работает, потому что
true
команда возвращает код завершения 0, который указывает на успех. Код в квадратных скобках работает, потому что значение$the_world_is_flat
идентично строковому литералуtrue
в правой части=
.Просто чтобы понять суть, рассмотрим следующие два фрагмента кода:
Этот код (если он запускается с правами root) перезагрузит ваш компьютер:
Этот код просто печатает "Хорошая попытка". Команда перезагрузки не вызывается.
Обновление (2014-04-14) Чтобы ответить на вопрос в комментариях относительно разницы между
=
и==
: AFAIK, нет никакой разницы.==
Оператор является Bash-специфический синоним=
, и, насколько я видел, они работают точно так же во всех контекстах.Заметьте, однако, что я специально говорю об операторах сравнения
=
и и==
строк, используемых в тестах[ ]
или[[ ]]
. Я не утверждаю , что=
и==
являются взаимозаменяемыми везде в Баш.Например, вы, очевидно, не можете выполнять присваивание переменных
==
, напримерvar=="foo"
(технически вы можете сделать это, но значениеvar
будет"=foo"
, потому что Bash не видит==
здесь оператора, он видит оператор=
(присваивания), за которым следует буквальное значение="foo"
, которое просто становится"=foo"
).Кроме того, хотя
=
и==
являются взаимозаменяемыми, вы должны иметь в виду, что как эти тесты работают , зависит от того, используете ли вы его внутри[ ]
или[[ ]]
, а также от того, заключены ли в кавычки операнды. Вы можете прочитать больше об этом в Advanced Bash Scripting Guide: 7.3 Другие операторы сравнения (прокрутите вниз до обсуждения=
и==
).источник
$the_world_is_flat && echo "you are in flatland!"
true
были сделаны относительно оригинального ответа. (Пересмотренный ответ 12 февраля 2014 г. не был представлен miku.) Я отредактировал ответ, включив в него как оригинал, так и пересмотренный. Тогда комментарии людей имеют смысл.true
. Есть ли способ? Я подозреваю, что многие программисты, которые привыкли к более строгим языкам, просматривают этот ответ, чтобы помочь им смешать немногоbash
клея, чтобы сделать их жизнь немного проще, хотели бы, чтобы===
оператор так, чтобы строки и «логические значения» на самом деле не были взаимозаменяемыми. Если они просто придерживаться 0 и 1 и использования ,(( $maybeIAmTrue ))
как предложено в Quolonel Вопрос «s ответ ?true
, но, как правило, не как нечто, с чем сравнивать переменную, поскольку реальноеtrue
не имеет значения само по себе. Все, что он делает, это устанавливает статус выхода0
, указывая на успех. Стоит отметить, что это по сути эквивалентно так называемой «нулевой команде» или:
. Что касается использования0
и1
, это то, что я делаю во всех моих сценариях в эти дни, где мне нужны логические значения. И я использую(( ))
оператор вместо[[ ]]
оценки. Так, например, если у меня естьflag=0
, то я могу сделатьif (( flag )); then ...
Используйте арифметические выражения.
Вывод:
источник
!
, иначе будет выполнено расширение истории.((! foo))
работает, так и делает! ((foo))
. Я люблю это решение, кстати. Наконец, краткий способ сделать логические переменные.((foo || bar))
работает как положено.(())
рекурсивно расширяет переменные, чего я не ожидал.foo=bar; bar=baz; ((foo)) && echo echo
ничего не печатает, но это правда сbaz=1
. Таким образом , вы можете поддерживатьfoo=true
иfoo=false
как 0 или 1, делаяtrue=1
.Короче говоря:
В Bash нет логических значений
У Bash есть логические выражения с точки зрения сравнения и условий. Тем не менее, то, что вы можете объявить и сравнить в Bash, это строки и числа. Вот и все.
Везде, где вы видите
true
илиfalse
в Bash, это либо строка, либо команда / встроенная команда, которая используется только для кода выхода.Этот синтаксис ...
по сути ...
Условие истинно, когда команда возвращает код выхода 0.
true
иfalse
являются Баш встроенных команды , а иногда также отдельными программы , которые не делают ничего , кроме возвращения соответствующего кода выхода.Условие выше эквивалентно:
При использовании квадратных скобок или
test
команды вы полагаетесь на код выхода этой конструкции. Имейте в виду , что[ ]
и[[ ]]
также в нескольких команд / встроенные функции, как и любой другой. Так ...соответствует
а
COMMAND
вот[[ 1 == 1 ]]
if..then..fi
Конструкция просто синтаксический сахар. Вы всегда можете просто запустить команды, разделенные двойным амперсандом, для того же эффекта:При использовании
true
иfalse
в этих конструкциях тестирования вы фактически передаете только строку"true"
или"false"
команду тестирования. Вот пример:Хотите верьте, хотите нет, но все эти условия дают один и тот же результат :
TL; DR; всегда сравнивайте со строками или числами
Чтобы это было понятно будущим читателям, я бы рекомендовал всегда использовать цитаты
true
иfalse
:ДЕЛАТЬ
не надо
Может быть
источник
T
иF
разъяснять, что это не настоящие логические значения.[
(то естьtest
)[[
и использовать тот, который подходит для его нужд.if ....; then mytest='-gt'; else mytest='-eq'; fi; #several lines of code; if [ "$var1" "$mytest" "$var2" ]; then ...; fi
Давным-давно, когда все, что у нас было, было
sh
, булевы были обработаны, полагаясь на соглашениеtest
программы, котороеtest
возвращает ложное состояние завершения, если выполняется без каких-либо аргументов.Это позволяет думать о переменной, которая не установлена как ложная, и переменной, установленной в любое значение, как истинная. Сегодня
test
он встроен в Bash и обычно известен своим псевдонимом из одного символа[
(или исполняемым файлом, который используется в оболочках, в которых его нет, как отмечает дольмен):Из-за соглашений о цитировании авторы сценариев предпочитают использовать составную команду,
[[
которая имитируетtest
, но имеет более приятный синтаксис: переменные с пробелами не нужно заключать в кавычки; Можно использовать&&
и в||
качестве логических операторов со странным приоритетом, и нет никаких ограничений POSIX на количество терминов.Например, чтобы определить, установлен ли флаг FLAG и число COUNT больше 1:
Это может привести к путанице, когда требуются пробелы, строки нулевой длины и нулевые переменные, а также когда ваш сценарий должен работать с несколькими оболочками.
источник
[
это не просто псевдоним внутриbash
. Этот псевдоним также существует в виде двоичного файла (или в виде ссылки, указывающей на него) и может использоваться с пустымsh
. Проверьтеls -l /usr/bin/\[
. Сbash
/zsh
вы должны вместо этого использовать[[
это действительно чистый внутренний и гораздо более мощный.[
иtest
также является командой BASH SHELL BUILTIN COMMAND согласно странице руководства Bash, поэтому проблем с производительностью не должно быть. То же самое, например, с Dash. (/ bin / sh может просто символическая ссылка на / bin / dash). Для того, чтобы использовать исполняемый файл вы должны использовать полный путь , т.е./usr/bin/\[
.В отличие от многих других языков программирования, Bash не разделяет свои переменные по «типу». [1]
Так что ответ довольно ясен. В Bash нет никаких логических переменных .
Однако:
Используя заявление объявления, мы можем ограничить присваивание значения переменным. [2]
r
Вариант вdeclare
иreadonly
используется для состояния явно , что переменные только для чтения . Я надеюсь, что цель ясна.источник
declare -ir false=0 true=1
? В чем преимущество использования массива?r
опции иreadonly
команде. Я бы сделал это так, как вы предложили в моих сценарияхdeclare and use boolean variables
Мы можем просто, более чем одним способом, имитировать / предполагать, что переменная имеет тип . Я не видел нигде упомянутого в вашем ответе.Вместо того, чтобы притворяться логическим и оставлять ловушку для будущих читателей, почему бы просто не использовать лучшее значение, чем true и false?
Например:
источник
0
применяется кfalse
и1
кtrue
. Что касается кодов0
завершения программы (которые исторически использует bash), то это для положительного результата,true
а все остальное - отрицательный / ошибка илиfalse
.POSIX (интерфейс переносимой операционной системы)
Я здесь скучаю по ключевому моменту - мобильности. Вот почему мой заголовок имеет POSIX сам по себе.
По сути, все проголосовавшие ответы верны, за исключением того, что они являются Bash слишком специфичны для .
В основном, я только хочу добавить больше информации о переносимости.
[
и]
скобки, такие как in[ "$var" = true ]
, не нужны, и вы можете опустить их и использоватьtest
команду напрямую:Важное примечание: я больше не рекомендую это, поскольку это медленно устаревают и более сложно объединять несколько утверждений.
Представьте, что эти слова
true
иfalse
значат для оболочки, проверьте сами:Но используя кавычки:
То же самое касается:
Оболочка не может интерпретировать это, кроме строки. Я надеюсь, что вы получаете представление о том, насколько хорошо это использовать правильное ключевое слово без кавычек .
Но никто не сказал это в предыдущих ответах.
Что это значит? Ну, несколько вещей.
Вы должны привыкнуть к тому, что логические ключевые слова фактически обрабатываются как числа, то есть
true
=0
иfalse
=1
, помните, что все ненулевые значения обрабатываются какfalse
.Так как они обрабатываются как числа, вы должны обращаться с ними так же, т.е. если вы определяете переменную, скажем:
Вы можете создать противоположное значение с помощью:
Как вы сами видите, оболочка печатает
true
строку в первый раз, когда вы ее используете, но с тех пор все работает через0
представлениеtrue
или1
представление числаfalse
соответственно.Наконец, что вы должны делать со всей этой информацией
Во-первых, одна хорошая привычка будет назначать
0
вместоtrue
;1
вместоfalse
.Вторая хорошая привычка - проверять, равна ли переменная нулю:
источник
Что касается синтаксиса, это простая методология, которую я использую (на примере) для последовательного и разумного управления булевой логикой:
Если переменная никогда не объявляется, ответ:
# false
Таким образом, простой способ установить переменный истинные ( с помощью этой методики синтаксиса) будет,
var=1
; наоборотvar=''
.Ссылка:
-n
= True, если длина строки var не равна нулю.-z
= True, если длина строки var равна нулю.источник
Во многих языках программирования логический тип является или реализуется как подтип целого числа, где
true
ведет себя как1
иfalse
ведет себя как0
:Логическое в C
Логическое в Python
Логическое в Java
Математически булева алгебра напоминает целочисленную арифметику по модулю 2. Поэтому, если язык не предоставляет родной булев тип, наиболее естественным и эффективным решением является использование целых чисел. Это работает практически с любым языком. Например, в Bash вы можете сделать:
человек Баш :
источник
За Билла Паркера проголосовали , потому что его определения противоположны обычному соглашению о коде. Обычно true определяется как 0, а false определяется как ненулевой. 1 будет работать для ложного, как и 9999 и -1. То же самое с возвращаемыми значениями функции - 0 - успех, а все ненулевое значение - неудача. Извините, у меня пока нет авторитета на улице, чтобы голосовать или отвечать ему напрямую.
Bash рекомендует теперь использовать двойные скобки вместо привычных скобок, и ссылка, которую дал Майк Холт, объясняет различия в том, как они работают. 7.3. Другие операторы сравнения
С одной стороны,
-eq
это числовой оператор, поэтому, имея кодвыдаст сообщение об ошибке, ожидая целочисленное выражение. Это относится к любому параметру, поскольку ни одно из них не является целочисленным значением. Тем не менее, если мы заключим в него двойные скобки, он не выдаст сообщение об ошибке, но даст неверное значение (ну, в 50% возможных перестановок). Он будет оцениваться как [[0 -eq true]] = success, но также как [[0 -eq false]] = success, что неверно (хммм .... как насчет того, что встроенная функция является числовым значением?).
Существуют и другие перестановки условного выражения, которые также дадут неправильный вывод. По сути, все (кроме состояния ошибки, указанного выше), которое устанавливает переменную в числовое значение и сравнивает ее со встроенной функцией истина / ложь, или устанавливает переменную со встроенной истиной / ложью и сравнивает ее с числовым значением. Кроме того, все, что устанавливает переменную во встроенное значение true / false и выполняет сравнение, используя
-eq
. Поэтому избегайте-eq
булевых сравнений и избегайте использования числовых значений для булевых сравнений. Вот краткое изложение перестановок, которые дадут неверные результаты:Итак, теперь к тому, что работает. Используйте встроенные true / false для сравнения и оценки (как отметил Майк Хант, не заключайте их в кавычки). Затем используйте одинарный или двойной знак равенства (= или ==) и одинарные или двойные скобки ([] или [[]]). Лично мне нравится знак двойного равенства, потому что он напоминает мне о логических сравнениях в других языках программирования, и двойные кавычки только потому, что я люблю печатать. Итак, эти работы:
Там у вас есть это.
источник
true
/false
встроенные модули не используются здесь (игнорировать то , что подсветка синтаксиса некоторых редакторов может означать), особенно в тех[…]
случаях , вы можете думать об этом как простая строка здесь (тот , который дается в качестве параметра в[
команде).Мои выводы и предложения немного отличаются от других постов. Я обнаружил, что могу использовать «булевы значения» в основном так же, как и на любом «обычном» языке, без предложенного «прыжка с обручем» ...
Нет необходимости
[]
или в явном сравнении строк ... Я пробовал несколько дистрибутивов Linux. Я тестировал Bash, Dash и BusyBox . Результаты всегда были одинаковыми. Я не уверен, о чем идет речь в оригинальных топ-постах. Может быть, времена изменились, и это все, что нужно сделать?Если вы установите переменную на
true
, она впоследствии оценивается как «утвердительная» в условном выражении. Установите егоfalse
, и он оценивается как «отрицательный». Очень просто! Единственное предостережение, что неопределенная переменная также оценивается как истина ! Было бы неплохо, если бы это произошло наоборот (как это было бы в большинстве языков), но это хитрость - вам просто нужно явно инициализировать ваши логические значения как true или false .Почему это работает так? Этот ответ в два раза. A) истина / ложь в оболочке действительно означает «нет ошибки» против «ошибки» (т. Е. 0 против чего-либо еще). Б) истина / ложь - это не значения, а операторы в сценариях оболочки! Что касается второй точки, выполнение
true
илиfalse
в строке само по себе устанавливает возвращаемое значение для блока, в котором вы находитесь, к этому значению, тоfalse
есть является декларацией «обнаружена ошибка», где true «очищает» это. Использование его с присваиванием переменной «возвращает» это в переменную. An неопределенные переменные оценивает , какtrue
в условном потому , что в равной степени имеет значение 0 или «нет» произошла ошибка.Смотрите пример строк Bash и результаты ниже. Проверьте сами, если хотите подтвердить ...
Урожайность
источник
Вот простой пример, который работает для меня:
источник
Вот реализация с короткими руками
if true
.Пример 1
Пример 2
источник
Я нашел существующие ответы смущающими.
Лично я просто хочу иметь что-то, что выглядит и работает как C.
Этот фрагмент работает много раз в день на производстве:
и чтобы все были счастливы, я проверил:
Который также работал нормально.
$snapshotEvents
Оценивает содержимое значения переменной. Так что вам нужно$
.Тебе не нужны скобки, я просто нахожу их полезными.
Проверено на: GNU Bash, версия 4.1.11 (2) -релиз
Руководство по Bash для начинающих , Machtelt Garrels, v1.11, 2008
источник
()
- не нужны. Мой единственный ответ - попробовать, кажется, это зависит от версии Bash, фактического выражения или контекста и тому подобного.Вот улучшение первоначального ответа miku, в котором рассматриваются опасения Денниса Уильямсона относительно случая, когда переменная не установлена:
И проверить, является ли переменная
false
:Что касается других случаев с неприятным содержимым в переменной, это проблема с любым внешним вводом, подаваемым в программу.
Любой внешний вход должен быть проверен, прежде чем доверять ему. Но эта проверка должна быть сделана только один раз, когда этот вход получен.
Это не должно влиять на производительность программы, делая это при каждом использовании переменной, как предлагает Деннис Уильямсон .
источник
Вы можете использовать shFlags .
Это дает вам возможность определить:
DEFINE_bool
Пример:
Из командной строки вы можете определить:
источник
Это тест скорости о различных способах проверки «логических» значений в Bash:
Было бы напечатать что-то вроде
источник
Альтернатива - использовать функцию
Определение функции менее интуитивно понятно, но проверить ее возвращаемое значение очень просто.
источник
Bash действительно запутывает вопрос с подобными
[
,[[
,((
,$((
и т.д.Все наступают на кодовые пространства друг друга. Я предполагаю, что это в основном историческое, где Башу приходилось притворяться, что он
sh
иногда.Большую часть времени я могу просто выбрать метод и придерживаться его. В этом случае я склонен объявлять (желательно в общем библиотечном файле, который я могу включить
.
в мои фактические сценарии).Затем я могу использовать
((
...))
арифметический оператор для проверки таким образом.Вы должны быть дисциплинированными. Вы
testvar
должны быть установлены$TRUE
или$FALSE
всегда.В
((
...))
компараторах вам не нужно предшествующее$
, что делает его более читабельным.Я могу использовать
((
...))
потому что$TRUE=1
и$FALSE=0
, т.е. числовые значения.Недостатком является необходимость
$
иногда использовать :что не так красиво.
Это не идеальное решение, но оно охватывает все случаи, когда мне нужно такое испытание.
источник