Почему между «[[» и «-e xxx» в ksh требуется пробел?

9

Например, следующая команда не работает:

if [[-e xyz]]; then echo File exists;fi

Кш дает следующую ошибку

[[-e: command not found

Это потому, что «[[-» неоднозначно?

AcBap
источник
2
[[является ключевым словом - предположительно дерево синтаксического анализа оболочки требует, чтобы ключевые слова были очерчены
пробелами
Другой способ взглянуть на это, вероятно, заключается в том, что вы могли бы написать функцию [[-, как бы оболочка узнала, что она анализирует «сделать флаг e на [[» вместо «сделать функцию [[- на e» »).
pbhj

Ответы:

15

Самое простое объяснение было бы, потому что в руководстве это выглядит [[ expression ]]так, что должно быть пространство между [[и expressionи закрытием ]]. Но, конечно, мы можем попытаться взглянуть на это более подробно. Оболочки имеют несколько сложную грамматику и в значительной степени полагаются на понятие «разбиение слов». В частности, руководство ksh (1) заявляет:

Оболочка начинает анализировать входные данные, разбивая их на слова. Слова, которые являются последовательностями символов, отделяются символами пробела без кавычек (пробел, табуляция и новая строка) или метасимволами (<,>, |,;, &, (и)). Помимо разграничения слов, пробелы и символы табуляции игнорируются, а символы новой строки обычно разделяют команды.

Таким образом, как указано в руководстве, последовательность символов [[-eсчитается словом оболочки. kshбудет искать такую ​​команду в списке встроенных и специальных операторов (например, forили while), затем искать внешнюю команду - и вуаля - ни одна не найдена, поэтому появляется сообщение об ошибке о команде не найдена.

В этом случае [[также не специальные метасимволы. Если бы это было так, то -eчасть [[-eбыла бы названа словом оболочки, а не аргументом для [[самого себя. Однако [[описывается как составная команда, а в руководстве говорится следующее:

Составные команды создаются с использованием следующих зарезервированных слов - эти слова распознаются только в том случае, если они не заключены в кавычки и если они используются в качестве первого слова команды (т. Е. Им не может предшествовать присвоение параметров или перенаправление):

Таким образом, [[чтобы быть распознанным как составная команда, это должно быть первое слово команды или списка команд, которое согласно предыдущему определению «слова» подразумевает, что оно должно быть отделено пробелами, символами табуляции или переводами строки от других слова / аргументы.


В комментариях вы спросили : «Почему анализатор не может остановиться, как только найдет» [[»шаблон, и рассматривает его как начало условной команды?» Краткий ответ, вероятно, объясняется тем, что: 1) влияние [синтаксиса, поскольку оно изначально было внешней командой, и для POSIX соответствие стандарту существует как внешняя команда даже сегодня, и 2) потому что анализатор оболочки построен так. Оболочка синтаксического анализатора может распознавать другие специальные символы, не разделенные пробелами, echo $((2+2))и (echo foobar)отлично работать. Возможно, в будущем, когда kshразработка возобновится, или, как представляется, будет форк или клон (например, mkshили pdksh), кто-то будет реализовывать синтаксис без пробелов в [[-e.

Смотрите также:

Сергей Колодяжный
источник
3
Я думаю, что цитата из руководства ksh действительно на месте. Это похоже на любой другой язык программирования: в C charэто ключевое слово, но вы все равно не можете писать charsomeletter = 'A';и ожидать, что парсер остановится после просмотра char.
Питер - Восстановить Монику
Я думаю, что основное различие между вашим примером "char" и символом "[[" в вопросе заключается в том, что буквенно-цифровой идентификатор, как правило, нуждается в разделителе пробела, чтобы отделить его от других; специальные символы в качестве токенов, с другой стороны, не нуждаются в разделителях пробелов.
AcBap
Точно. Я не уверен, что сравнение с C полезно. В Си можно сказать i--<=++j, и у компилятора нет проблем с синтаксическим анализом i -- <= ++ j.
Скотт
@ Скотт Я думаю, что сравнение C полезно (и что это вторично, что идентификаторы C допускают только буквенно-цифровые символы и _). Кш имеет (как оператор , так и (echo hello)разбирает как ( echo hello ). Это if, {, [[и другие ключевые слова , и ifx, {xи [[xкаждый один маркер - например , как charsomeletterэто один C маркер. Напротив, без кавычек (xв ksh есть два токена - например, как i--два токена в C. То, что концептуально даже означает быть оператором, различается между оболочками в стиле Борна (например, ksh) и C. Но Питер А. Шнайдер указал на реальное лексическое сходство.
Элия ​​Каган
2

Важно отметить, что [это команда, и в [[ее основе лежит ключевое слово shell в bash и ksh [.

[[используется аналогично [. Иногда вы можете даже заменить [ ]с [[ ]]без каких - либо изменений в поведении. При использовании [, как и любой команды, между командой и ее аргументами обязательно должен быть пробел. То же самое относится и к [[.

Раньше было только /usr/bin/[. Сейчас большинство оболочек [встроено для повышения эффективности, но синтаксис тот же. В оболочках, которые предоставляют [[, он функционирует как более универсальная альтернатива [.

Вот описание для [Bash:

$ help [
[: [ arg... ]
    Evaluate conditional expression.

    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.

Так [что эквивалентно test(кроме ожидания ]аргумента в самом конце). help testдаст еще больше подробностей об этом. Вы можете сравнить это с help [[.

Также есть справочная страница для внешней команды [( man \[).

На случай, если

if [[-e
  • Ни там, [ни [[там нет команды. Полное слово [[-eесть.
  • Это if [[-eделает тест на истину / ложь. Так есть ли команда [[-e?

Это потому, что «[[-» неоднозначно?

Да. Или нет [[-eэто то, что есть: ничего, что оболочка не понимает, поэтому она предполагает, что это ее собственная команда. ;-)

Rinzwind
источник
«% help [[» говорит, что «[[» является условной командой. Почему синтаксический анализатор не может остановиться, как только находит шаблон «[[» и рассматривает его как начало условной команды?
AcBap
@Myloti [[-e- это потенциально допустимое (если странно выглядящее) имя команды.
Гордон Дэвиссон
2

Пространство является разделителем и является обязательным. Как вы можете видеть из shellcheck:

$ shellcheck gmail-browse-msgs-algorithm.sh

In gmail-browse-msgs-algorithm.sh line 847:
        [[$Today != "${DaysArr[ i + DAY_DELETED_ON_NDX ]}" ]] && continue
          ^-- SC1035: You need a space after the [[ and before the ]].

(Поддерживаются как ksh, так и bash, [[и они не работают без пробела. Shellcheck выдает именно такой вывод с помощью похожих сценариев ksh и bash, содержащих эту строку с ошибками.)

Для чего нужны разделители, имеет отношение к токенам и лексиконам .

WinEunuuchs2Unix
источник
Пожалуйста, обратите внимание, что ОП спросил о kshоболочке в вопросе. Bash заимствует [[оператору kshи в этом вопросе их поведение идентично, но я был бы осторожен предположений , поскольку есть некоторые существенные различия между kshи bashповедения и внутренних органов . Это потому, что shellcheck работает на скрипте bash, он не обязательно может быть подходящим инструментом для скриптов ksh. Просто что-то иметь в виду при приближении к разным снарядам
Сергей Колодяжный
@SergiyKolodyazhnyy Я был оппортунистом, используя shellcheck, чтобы выделить [[встроенные правила. Я ни в коем случае не делал вывод, что kshэто оболочка, в которой shellcheckмогут быть обнаружены ошибки. Я надеюсь, что другие ценят kshи bashявляются двумя разными интерпретаторами. Спасибо за упоминание этого. Также стоит отметить [[встроенный bash, а [внешнюю команду.
WinEunuuchs2Unix
На самом деле [это также встроенная в bash :) manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.html Но вы не за горами - [или вам testтребуется внешняя команда. В те времена, когда оригинальная оболочка Bourne [была фактически внешней командой, она все еще существует в настоящее время, /usr/bin/[поскольку POSIX требует, чтобы она была внешней командой pubs.opengroup.org/onlinepubs/009695399/utilities/test.html POSIX требуется очень мало для быть встроенным pubs.opengroup.org/onlinepubs/009695399/idx/sbi.html Встроенный [- для эффективности
Сергей Колодяжный
2
Шеллчек знает ksh; используйте hashbang или -s ksh. Кстати, ksh и bash имеют [[«встроенный», но, в отличие от этого, это ключевое слово[ - встроенная оболочка . (ksh :; whence -v [ [[bash type [ [[:) Встроенные и внешние команды синтаксически похожи. Один [[из отличий от этого [заключается в том, что он [[подавляет некоторые расширения в своих аргументах, которые он не может использовать как встроенные - так же, как {и при группировке, если бы он не был встроенным. Это может быть то, почему {x(или [[x) быть одним жетоном кажется странным. Я думаю, что правильно сказать, что встроенные функции и ключевые слова лексически, но не синтаксически похожи. @SergiyKolodyazhnyy
Каган
1
@EliahKagan На самом деле, я разместил вопрос на U & L, чтобы получить точный ответ о том, что POSIX думает об этой ситуации unix.stackexchange.com/questions/526574/… Язык оболочки достаточно сложен, так что, надеюсь, кто-то сможет объяснить это в более формальных терминах
Сергей Колодяжный
1

[[может быть внешней командой! То есть это может быть программа, а не какой-то синтаксис, поддерживаемый вашей оболочкой напрямую. Поддержка синтаксиса без пробелов возможна, kshно в системах с внешним [[интерфейсом она не будет работать, поэтому по соображениям совместимости лучше сохранить необходимое пространство.

[[Например, BusyBox предоставляет в качестве внешней команды .

DarkDust
источник
0

Так как [[-eможет участвовать в расширении оболочки (его можно использовать как

echo [[-e]*

для того, чтобы перечислить все файлы, начинающиеся с буквы между [и eвключительно), было бы полным беспорядком, если бы [и ]были специальными символами, не участвующими в нормальном разделении слов с пробелами.


источник