ZSH-определенной функцией являются суффиксные псевдонимы, установленные путем предоставления alias
-s
флаг:
alias -s ext=program
Если данное расширение имеет суффиксный псевдоним, можно выполнить файл с тем расширением непосредственно, и ZSH запустит данную программу и передаст имя файла как аргумент. Таким образом, если вышеупомянутый псевдоним в действительности, эти строки эквивалентны:
/path/to/foo.ext
program /path/to/foo.ext
В Вашем сценарии существует две ошибки. Прежде всего, Вам нужно пространство между !
и $flag
, иначе оболочка ищет названную команду !$flag
. Вторая ошибка - это -eq
для целочисленных сравнений, но Вы используете его на строке. В зависимости от Вашей оболочки любой Вы будете видеть сообщение об ошибке, и цикл продолжится навсегда потому что условие [ "$x" -eq "true" ]
не может быть верным, или каждое значение нецелого числа будут рассматривать как 0, и цикл выйдет при вводе какой-либо строки (включая false
) кроме числа, отличающегося от 0.
В то время как ! $flag
корректно, это - плохая идея рассматривать строку как команду. Это работало бы, но это будет очень чувствительно к изменениям в Вашем сценарии, так как необходимо было бы удостовериться это $flag
никогда не может быть совсем не true
или false
. Было бы лучше использовать сравнение строк здесь, как в тесте ниже.
flag=false
while [ "$flag" != "true" ]
do
read x
if [ "$x" = "true" ]
then
flag=true
fi
echo "${x} : ${flag}"
done
Существует, вероятно, лучший способ выразить логику, которая Вы после. Например, Вы могли сделать бесконечный цикл и повредить его при обнаружении условия завершения.
while true; do
read -r x
if [ "$x" = "true" ]; then break; fi
echo "$x: false"
done
Это работает на меня:
flag=false
while [[ "$flag" == "false" ]]
do
read x
if [[ "$x" == "true" ]]
then
flag=true
fi
echo "${x} : ${flag}"
done
Но на самом деле то, что необходимо сделать, заменить Ваш while
с:
while ! $flag
Хотя в Bash нет булевых переменных, эмулировать их с помощью арифметической оценки очень просто.
flag= # False
flag=0 # False
flag=1 # True (actually any integer number != 0 will do, but see remark below about toggling)
flag="some string" # Maybe False (make sure that the string isn't interpreted as a number)
if ((flag)) # Test for True
then
: # do something
fi
if ! ((flag)) # Test for False
then
: # do something
fi
flag=$((1-flag)) # Toggle flag (only works when flag is either empty or unset, 0, 1, or a string which doesn't represent a number)
Это также работает в кш. Я не удивлюсь, если она работает во всех POSIX-совместимых оболочках, но не проверил стандарт.
[ ${FOO:-0} == 0 ] && FOO=1 || FOO=0
или даже:
[ ${FOO:-false} == false ] && FOO=true || FOO=false
должен выполнить работу
Если вы можете быть абсолютно уверены, что переменная будет содержать либо 0 или 1, вы можете использовать побитовый оператор XOR-equal для переключения между двумя значениями:
$ foo=0
$ echo $foo
0
$ ((foo ^= 1))
$ echo $foo
1
$ ((foo ^= 1))
$echo $foo
0
until
является сокращением отwhile !
(и until
, в отличие от !
это Борн ), так что вы можете сделать:
flag=false
until "$flag"
do
IFS= read -r x
if [ "$x" = true ]
then
flag=true
fi
printf '%s\n' "$x : $flag"
done
Что должно совпадать с:
flag=false
while ! "$flag"
do
IFS= read -r x
if [ "$x" = true ]
then
flag=true
fi
printf '%s\n' "$x : $flag"
done
Вы также можете написать это как:
until
IFS= read -r x
printf '%s\n' "$x"
[ "$x" = true ]
do
continue
done
Часть между until
/ while
и do
не обязательно должна быть одной командой.
!
— это ключевое слово в синтаксисе оболочки POSIX. Он должен быть разделен, токен отделен от того, что следует за ним, и должен быть первым токеном, который предшествует конвейеру.(! foo | bar
отменяет конвейер, а foo | ! bar
недействителен, хотя некоторые оболочки принимают его как расширение ).
!true
интерпретируется как команда !true
, которая вряд ли существует. ! true
должно работать. !(true)
должен работать в оболочках, совместимых с POSIX -, поскольку !
ограничен, поскольку за ним следует токен (
, но на практике он не работает в ksh
/bash -O extglob
, где он конфликтует с !(pattern)
расширенный оператор glob nor zsh (, за исключением эмуляции схемы ), где он конфликтует с glob(qualifiers)
с bareglobqual
и glob(group)
без.
В оболочке нет понятия логической переменной.
Переменные оболочки могут быть толькоtext
(строкой ), и в некоторых случаях этот текст может интерпретироваться как целое число (1
, 0xa
, 010
и т. д. ).
Таким образом, a flag=true
не означает истинности или ложности оболочки вообще.
Что можно сделать, так это либо сравнить строки [ "$flag" == "true" ]
, либо использовать содержимое переменной в какой-либо команде и проверить ее последствия , например выполнить true
(, потому что есть исполняемый файл с именем true
и один вызываетсяfalse
)как команда и проверяется, равен ли код выхода этой команды нулю (успешно ).
$flag; if [ "$?" -eq 0 ]; then... fi
Или короче:
if "$flag"; then... fi
Если содержимое переменной используется в качестве команды, !
можно использовать для отмены статуса выхода команды, если между обоими(! cmd
)есть пробел, как в:
if ! "$flag"; then... fi
Скрипт должен измениться на:
flag=false
while ! "$flag"
do
read x
if [ "$x" == "true" ]
then
flag=true
fi
echo "${x} : ${flag}"
done
Использовать числовые значения и арифметические расширения .
В этом случае код выхода $((0))
— 1
, а код выхода $((1))
— 0
.
В bash, ksh и zsh арифметика может выполняться внутри заметки((..))
(о том, что начальный $
отсутствует ).
flag=0; if ((flag)); then... fi
Портативная версия этого кода более запутана:
flag=0; if [ "$((flag))" -eq 0 ]; then... fi # test for a number
flag=0; if [ "$((flag))" == 0 ]; then... fi # test for the string "0"
В bash/ksh/zsh можно сделать:
flag=0
while ((!flag))
do
read x
[ "$x" == "true" ] && flag=1
echo "${x} : ${flag}"
done
Вы можете «Инвертировать логическую переменную» (, если она содержит числовое значение )как:
((flag=!flag))
Это изменит значение flag
либо на 0
, либо на 1
.
Примечание.:Пожалуйста, проверьте наличие ошибок в https://www.shellcheck.net/, прежде чем публиковать свой код в виде вопроса, много раз этого достаточно, чтобы найти проблему.