Например, следующая команда не работает:
if [[-e xyz]]; then echo File exists;fi
Кш дает следующую ошибку
[[-e: command not found
Это потому, что «[[-» неоднозначно?
Например, следующая команда не работает:
if [[-e xyz]]; then echo File exists;fi
Кш дает следующую ошибку
[[-e: command not found
Это потому, что «[[-» неоднозначно?
Ответы:
Самое простое объяснение было бы, потому что в руководстве это выглядит [[ expression ]]
так, что должно быть пространство между [[
и expression
и закрытием ]]
. Но, конечно, мы можем попытаться взглянуть на это более подробно. Оболочки имеют несколько сложную грамматику и в значительной степени полагаются на понятие «разбиение слов». В частности, руководство ksh (1) заявляет:
Оболочка начинает анализировать входные данные, разбивая их на слова. Слова, которые являются последовательностями символов, отделяются символами пробела без кавычек (пробел, табуляция и новая строка) или метасимволами (<,>, |,;, &, (и)). Помимо разграничения слов, пробелы и символы табуляции игнорируются, а символы новой строки обычно разделяют команды.
Таким образом, как указано в руководстве, последовательность символов [[-e
считается словом оболочки. ksh
будет искать такую команду в списке встроенных и специальных операторов (например, for
или while
), затем искать внешнюю команду - и вуаля - ни одна не найдена, поэтому появляется сообщение об ошибке о команде не найдена.
В этом случае [[
также не специальные метасимволы. Если бы это было так, то -e
часть [[-e
была бы названа словом оболочки, а не аргументом для [[
самого себя. Однако [[
описывается как составная команда, а в руководстве говорится следующее:
Составные команды создаются с использованием следующих зарезервированных слов - эти слова распознаются только в том случае, если они не заключены в кавычки и если они используются в качестве первого слова команды (т. Е. Им не может предшествовать присвоение параметров или перенаправление):
Таким образом, [[
чтобы быть распознанным как составная команда, это должно быть первое слово команды или списка команд, которое согласно предыдущему определению «слова» подразумевает, что оно должно быть отделено пробелами, символами табуляции или переводами строки от других слова / аргументы.
В комментариях вы спросили : «Почему анализатор не может остановиться, как только найдет» [[»шаблон, и рассматривает его как начало условной команды?» Краткий ответ, вероятно, объясняется тем, что: 1) влияние [
синтаксиса, поскольку оно изначально было внешней командой, и для POSIX соответствие стандарту существует как внешняя команда даже сегодня, и 2) потому что анализатор оболочки построен так. Оболочка синтаксического анализатора может распознавать другие специальные символы, не разделенные пробелами, echo $((2+2))
и (echo foobar)
отлично работать. Возможно, в будущем, когда ksh
разработка возобновится, или, как представляется, будет форк или клон (например, mksh
или pdksh
), кто-то будет реализовывать синтаксис без пробелов в [[-e
.
[[
называется «зарезервированным словом» (см. Раздел 2.9 языка командных команд оболочки ). По определению POSIX зарезервированное слово должно быть разделено пробелами. В отличие (
от этого, оператор является стандартным, и в разделе 2.9 говорится, что «представления включают интервалы между токенами в некоторых местах, где <blank>
s не требуется (когда один из токенов является оператором)». См. Соответствующее обсуждение: грамматика оболочки POSIX: почему группе скобок нужен первый пробел, а вспомогательной - нет?char
это ключевое слово, но вы все равно не можете писать charsomeletter = 'A';
и ожидать, что парсер остановится после просмотра char
.
i--<=++j
, и у компилятора нет проблем с синтаксическим анализом i -- <= ++ j
.
_
). Кш имеет (
как оператор , так и (echo hello)
разбирает как ( echo hello )
. Это if
, {
, [[
и другие ключевые слова , и ifx
, {x
и [[x
каждый один маркер - например , как charsomeletter
это один C маркер. Напротив, без кавычек (x
в ksh есть два токена - например, как i--
два токена в C. То, что концептуально даже означает быть оператором, различается между оболочками в стиле Борна (например, ksh) и C. Но Питер А. Шнайдер указал на реальное лексическое сходство.
Важно отметить, что [
это команда, и в [[
ее основе лежит ключевое слово 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
это то, что есть: ничего, что оболочка не понимает, поэтому она предполагает, что это ее собственная команда. ;-)
[[-e
- это потенциально допустимое (если странно выглядящее) имя команды.
Пространство является разделителем и является обязательным. Как вы можете видеть из 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, содержащих эту строку с ошибками.)
Для чего нужны разделители, имеет отношение к токенам и лексиконам .
ksh
оболочке в вопросе. Bash заимствует [[
оператору ksh
и в этом вопросе их поведение идентично, но я был бы осторожен предположений , поскольку есть некоторые существенные различия между ksh
и bash
поведения и внутренних органов . Это потому, что shellcheck работает на скрипте bash, он не обязательно может быть подходящим инструментом для скриптов ksh. Просто что-то иметь в виду при приближении к разным снарядам
[[
встроенные правила. Я ни в коем случае не делал вывод, что ksh
это оболочка, в которой shellcheck
могут быть обнаружены ошибки. Я надеюсь, что другие ценят ksh
и bash
являются двумя разными интерпретаторами. Спасибо за упоминание этого. Также стоит отметить [[
встроенный bash, а [
внешнюю команду.
[
это также встроенная в 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 Встроенный [
- для эффективности
ksh
; используйте hashbang или -s ksh
. Кстати, ksh и bash имеют [[
«встроенный», но, в отличие от этого, это ключевое слово[
- встроенная оболочка . (ksh :; whence -v [ [[
bash type [ [[
:) Встроенные и внешние команды синтаксически похожи. Один [[
из отличий от этого [
заключается в том, что он [[
подавляет некоторые расширения в своих аргументах, которые он не может использовать как встроенные - так же, как {
и при группировке, если бы он не был встроенным. Это может быть то, почему {x
(или [[x
) быть одним жетоном кажется странным. Я думаю, что правильно сказать, что встроенные функции и ключевые слова лексически, но не синтаксически похожи. @SergiyKolodyazhnyy
[[
может быть внешней командой! То есть это может быть программа, а не какой-то синтаксис, поддерживаемый вашей оболочкой напрямую. Поддержка синтаксиса без пробелов возможна, ksh
но в системах с внешним [[
интерфейсом она не будет работать, поэтому по соображениям совместимости лучше сохранить необходимое пространство.
[[
Например, BusyBox предоставляет в качестве внешней команды .
Так как [[-e
может участвовать в расширении оболочки (его можно использовать как
echo [[-e]*
для того, чтобы перечислить все файлы, начинающиеся с буквы между [
и e
включительно), было бы полным беспорядком, если бы [
и ]
были специальными символами, не участвующими в нормальном разделении слов с пробелами.
[[
является ключевым словом - предположительно дерево синтаксического анализа оболочки требует, чтобы ключевые слова были очерчены