Я хочу попробовать простой скрипт
flag=false
while !$flag
do
read x
if [ "$x" -eq "true" ]
then
flag=true
fi
echo "${x} : ${flag}"
done
Но когда я запускаю его, если я набираю true
, я увижу это x="true"
и flag="true"
, но цикл не заканчивается. Что не так со сценарием? Как правильно инвертировать логическую переменную?
Ответы:
В вашем скрипте есть две ошибки. Во-первых, вам нужен пробел между
!
и$flag
, в противном случае оболочка ищет команду с именем!$flag
. Вторая ошибка --eq
для целочисленных сравнений, но вы используете ее в строке. В зависимости от вашей оболочки, либо вы увидите сообщение об ошибке, и цикл будет продолжаться вечно, потому что условие[ "$x" -eq "true" ]
не может быть истинным, либо каждое нецелое значение будет рассматриваться как 0, и цикл завершится, если вы введете какую-либо строку (включаяfalse
) кроме числа, отличного от 0.Хотя
! $flag
это правильно, плохая идея рассматривать строку как команду. Это будет работать, но это будет очень чувствительно к изменениям в вашем скрипте, так как вам нужно убедиться, что$flag
это никогда не может быть чем-либо, кромеtrue
илиfalse
. Было бы лучше использовать сравнение строк здесь, как в тесте ниже.Вероятно, есть лучший способ выразить логику, которую вы ищете. Например, вы можете сделать бесконечный цикл и разорвать его, когда обнаружите условие завершения.
источник
[
встроенной командой изksh
,[ x -eq y ]
возвращает истину еслиx
арифметических выражений решает в том же количестве, вy
арифметическом выражении , так, например ,x=2 true=1+1 ksh -c '[ x -eq true ] && echo yes'
было бы выход да.Хотя в Bash нет логических переменных, их очень легко эмулировать с помощью арифметической оценки.
Это также работает в ksh. Я не удивлюсь, если он работает во всех POSIX-совместимых оболочках, но не проверил стандарт.
источник
! ! ((val))
в Bash, как в C или C ++? Например, еслиval
0, оно остается 0 после! !
. Еслиval
1, то остается 1 после! !
. Если значениеval
равно 8, оно уменьшается до 1 после! !
. Или мне нужно задать еще один вопрос?Если вы можете быть абсолютно уверены, что переменная будет содержать 0 или 1, вы можете использовать побитовый оператор XOR-equal для переключения между двумя значениями:
источник
Это работает для меня:
Но, на самом деле, то, что вы должны сделать, это заменить вашу
while
:источник
В оболочке нет понятия булевой переменной.
Переменные оболочки могут быть только
text
(строка), и, в некоторых случаях, этот текст может быть истолкован как целое число (1
,0xa
,010
и т.д.).Следовательно, a не
flag=true
подразумевает никакой правдивости или ложности для оболочки.строка
То, что можно сделать, - это либо сравнение строк,
[ "$flag" == "true" ]
либо использование содержимого переменной в некоторой команде, и проверка ее последствий , например, выполнениеtrue
(потому что есть и вызываемый исполняемый файл,true
и вызываемыйfalse
) в качестве команды, и проверка, равен ли код выхода этой команды нулю. (успешно).Или короче:
Если содержимое переменной используется в качестве команды, то
!
можно использовать ее для отмены статуса завершения команды, если между двумя (! cmd
) существует пробел , как в:Сценарий должен измениться на:
целое число
Используйте числовые значения и арифметические расширения .
В этом случае код выхода
$((0))
is1
и код выхода$((1))
is0
.В bash, ksh и zsh арифметика может выполняться внутри a
((..))
(обратите внимание, что запуск$
отсутствует).flag=0; if ((flag)); then ... fi
Портативная версия этого кода более запутанная:
В bash / ksh / zsh вы можете сделать:
альтернативно
Вы можете «инвертировать логическую переменную» (при условии, что она содержит числовое значение) как:
((flag=!flag))
Это изменит значение
flag
либо на,0
либо1
.Примечание . Пожалуйста, проверьте ошибки на https://www.shellcheck.net/, прежде чем публиковать свой код в виде вопроса. Этого достаточно, чтобы найти проблему.
источник
until
это сокращение отwhile !
(иuntil
, в отличие от!
Борна), так что вы можете сделать:Который должен быть таким же, как:
Вы также можете написать это как:
Часть между
until
/while
иdo
не должна быть единой командой.!
является ключевым словом в синтаксисе оболочки POSIX. Он должен быть разделен, токен отделен от следующего и быть первым токеном, предшествующим конвейеру (! foo | bar
отрицает конвейер иfoo | ! bar
является недействительным, хотя некоторые оболочки принимают его как расширение).!true
интерпретируется как!true
команда, которая вряд ли существует.! true
должно сработать.!(true)
должен работать в POSIX-совместимых оболочках, поскольку!
он разделен, поскольку за ним следует(
токен, но на практике он не работает вksh
/bash -O extglob
там, где он конфликтует с!(pattern)
оператором расширенного glob, ни с zsh (кроме эмуляции sh), где он конфликтуетglob(qualifiers)
сbareglobqual
иglob(group)
без.источник
или даже:
должен делать работу
источник