Почему между & ldquo; [[& rdquo; требуется пробел и & ldquo; -e xxx & rdquo; в кш?

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

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

ksh выдает следующую ошибку

[[-e: command not found

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

9
задан 23 June 2019 в 11:13

5 ответов

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

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

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

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

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

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


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

См. Также:

15
ответ дан 23 June 2019 в 11:13

Важно отметить, что [ является командой, а ключевое слово 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 - это то, что есть: ничего, что оболочка не понимает, поэтому она предполагает, что это ее собственная команда. ;-)

2
ответ дан 23 June 2019 в 11:13

Пространство является разделителем и является обязательным. Как вы можете видеть из 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-скрипты, содержащие эту строку с ошибками.)

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

2
ответ дан 23 June 2019 в 11:13

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

BusyBox предоставляет [[ как внешнюю команду , например.

1
ответ дан 23 June 2019 в 11:13

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

echo [[-e]*

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

0
ответ дан 23 June 2019 в 11:13

Другие вопросы по тегам:

Похожие вопросы: