Почему `==` ведет себя по-разному внутри `[…]` в zsh и bash?

9

Я получаю то, что ожидал, делая это в bash:

[ "a" == "a" ] && echo yes

Это дало мне yes.

Но когда я делаю это zsh, я получаю следующее:

zsh: = not found

Почему одна и та же команда ( /usr/bin/[) ведет себя по-разному в разных оболочках?

Джонсон Стюард
источник
5
это не та же команда - это встроенная функция, найденная до $PATHпоиска. и ==не действует testсинтаксис для /usr/bin/[Анвэя. Просто =в порядке.
mikeserv

Ответы:

18

Этого нет /usr/bin/[ни в одном из снарядов. В Bash вы используете встроенную команду test/[ и аналогично в zsh .

Разница в том, что zsh также имеет =расширение : =fooрасширяет путь к fooисполняемому файлу. Это означает, ==что вы пытаетесь найти команду, вызываемую =в вашемPATH . Поскольку эта команда не существует, вы получаете ошибку

zsh: = not found

что вы видели (и на самом деле, это то же самое произойдет, даже если вы на самом деле использовали /usr/bin/[).


Вы можете использовать ==здесь, если вы действительно хотите. Это работает, как вы ожидали в Zsh:

[ "a" "==" "a" ] && echo yes

потому что цитирование препятствует =wordзапуску расширения. Вы также можете отключить эту equalsопцию с помощью setopt noequals.


Тем не менее, вы бы лучше:

  • Используя single =, POSIX-совместимый тест на равенство ; или
  • Еще лучше, используя [[условные выражения== в Bash и Zsh . В общем, [[все лучше и безопаснее, в том числе избегая подобных проблем (и других), используя специальные правила синтаксического анализа внутри.
Майкл Гомер
источник
Какая точная разница между [и [[? (Поиск в Google [ vs [[дает мне результаты vsтолько, LOL)
Джонсон Стюард
2
[[поддерживает более широкий диапазон тестов в обоих случаях и имеет собственные правила синтаксического анализа, позволяющие избежать необходимости заключать в кавычки переменные, операторы и т. д. Если вы специально используете Bash или Zsh, используйте [[. Если вы пишете портативный сценарий, запись в POSIX-совместимые [/ testкоманды (которая может или не может быть реальной командой на вашей работающую системе).
Майкл Гомер
1
Просто используйте [[там и забудьте о [существовании.
Майкл Гомер
1
Вы знаете ... я не согласен с вашей рекомендацией. [[по- другому способен. попробуйте это с этим for f in *; do [ -e "$f" ] && for a in f d h p S b c; do [ "-$a" "$f" ] && for p in r w x u g; do [ "-$p" "$f" ] || p=-; a=$a$p; done && break; done && printf "%s:\t%s\n" "$a" "$f"; done.
mikeserv
3
Ну, =/ ==, возможно , один случай , когда [[не лучше [, так как [[ a == b ]]это делает «а» соответствует «B» образец и не является «» равно «Ъ» , как и следовало ожидать. Это означает, что вам нужно написать, [[ $a == "$b" ]]например. По крайней мере, с [командой, если вы знаете, как работает синтаксический анализ команд, вы знаете, что вам нужно написать ее, [ "$a" = "$b" ]чтобы предотвратить оператор split + glob, как в других командах. Имея это в виду и если вы не используете -a или -o, [это безопасно в реализациях, соответствующих POSIX.
Стефан Шазелас
2

И zsh, и bash дают один и тот же ответ ( typeтоже встроен для обеих оболочек):

$ type -a [
[ is a shell builtin
[ is /usr/bin/[
Jshura
источник
2

[ встроенная команда оболочки в bash и zsh:

$ type [
[ is a shell builtin

Из документации команд Shell Builtin :

Встроенные команды содержатся внутри самой оболочки . Когда имя встроенной команды используется в качестве первого слова простой команды (см. Простые команды ), оболочка выполняет команду напрямую, без вызова другой программы. Встроенные команды необходимы для реализации функциональности, которую невозможно или неудобно получить с помощью отдельных утилит.

Официальная документация ( $ help test) позволяет использовать только =:

STRING1 = STRING2

Истинно, если строки равны.

Итак, правильное выражение будет:

$ [ "a" = "a" ] && echo yes
yes

То, что происходит, - то, что bash немного менее строг. Поддержка ==оператора с [ расширением bash, похоже, не рекомендуется использовать:

строка1 == строка2

строка1 = строка2

Истинно, если строки равны. При использовании с командой [[] выполняется сопоставление с образцом, как описано выше (см. Условные конструкции ).

'=' должен использоваться с командой test для соответствия POSIX.

Если вы хотите использовать ==, вы должны использовать [[ключевое слово:

$ [[ "a" == "a" ]] && echo yes
yes

Имейте в виду, что [[он менее переносим (это не POSIX). Но и bash, и zsh поддерживают это.

Zuazo
источник
1

В обеих оболочках, bashи zsh, [утилита встроена в оболочку. Это реализация оболочки этого инструмента, она используется в предпочтении двоичному /usr/bin/[. Разные результаты, с которыми вы сталкиваетесь, вызваны разными реализациями.


В bash, [утилита принимает CONDITIONAL EXPRESSIONSв качестве [[составной команды. Согласно man-странице bashs оба =и ==действительны:

string1 == string2
string1 = string2
        True if the strings are equal.  = should be used with the test command for POSIX
        conformance.

В zsh, [утилита пытается реализовать POSIX и его расширения, где они указаны. В спецификации тестовой утилиты POSIX не существует ==оператор , определенный.

хаос
источник