В чем разница между [[$ a == z *]] и [$ a == z *]?

35

Есть ли разница между этими двумя.

[[ $a == z* ]]

а также

[ $a == z* ] 

Могу ли я иметь пример, где они будут иметь разные выходы?

Кроме того, чем [[ ]]отличается работа от [ ]?

Munish
источник

Ответы:

41

Разница между [[ … ]]и [ … ]в основном заключается в использовании одинарной или двойной скобки - bash . Важно то, что [[ … ]]это специальный синтаксис, а [название команды выглядит смешно. [[ … ]]имеет специальные правила синтаксиса для того, что внутри, [ … ]нет.

С добавлением морщины подстановочного знака, вот как [[ $a == z* ]]оценивается:

  1. Разбор команды: это [[ … ]]условная конструкция вокруг условного выражения $a == z*.
  2. Разберите условное выражение: это ==бинарный оператор с операндами $aи z*.
  3. Разверните первый операнд в значение переменной a.
  4. Оцените ==оператор: проверьте, соответствует ли значение переменной aшаблону z*.
  5. Оцените условное выражение: его результат является результатом условного оператора.
  6. Команда теперь оценивается, ее статус равен 0, если условное выражение было истинным, и 1, если оно было ложным.

Вот как [ $a == z* ]это оценивается:

  1. Разбираем команды: это [команда с аргументами , образуемых оценки слова $a, ==, z*, ].
  2. Разверните $aв значение переменной a.
  3. Выполните разделение слов и генерацию имени файла по параметрам команды.
    • Например, если значение aявляется строка 6 символов foo b*(полученная , например a='foo b*') , и список файлов в текущем каталоге ( bar, baz, qux, zim, zum), то результат разложения является следующим списком слов: [, foo, bar, baz, ==, zim, zum, ].
  4. Запустите команду [с параметрами, полученными на предыдущем шаге.
    • С приведенными выше примерами значения [команда жалуется на синтаксическую ошибку и возвращает статус 2.

Примечание. На [[ $a == z* ]]шаге 3 значение aне подвергается разделению слов и генерации имени файла, поскольку оно находится в контексте, где ожидается одно слово (левый аргумент условного оператора ==). В большинстве случаев, если в этой позиции имеет смысл одно слово, расширение переменной ведет себя так же, как в двойных кавычках. Однако из этого правила есть исключение: [[ abc == $a ]]если значение aсодержит подстановочные знаки, то aсопоставляется с шаблоном подстановочных знаков. Например, если значение aравно true, a*то [[ abc == $a ]]это правда (потому что подстановочный знак, *полученный при раскрытии $aсовпадений без кавычек *), тогда [[ abc == "$a" ]]как ложно (потому что обычный символ*исходя из приведенного расширения $aне совпадает bc). Внутри [[ … ]], двойные кавычки не делают разницы, кроме как на правой стороне операторов строки соответствия ( =, ==, !=и =~).

Жиль "ТАК - прекрати быть злым"
источник
39

[это псевдоним для testкоманды. В Unix версии 6 была ifкоманда, но в версии 7 (1979) появилась новая оболочка Bourne, в которой было несколько программных конструкций, включая конструкцию if-then-else-elif-fi, а в Unix версии 7 добавлена testкоманда, которая выполняла большую часть «тесты», которые проводились ifкомандой в старых версиях.

[был сделан псевдоним, testи оба были встроены в оболочку в Unix System III (1981) . Хотя следует отметить, что некоторые варианты Unix не имели [команды намного позже ( до начала 2000-х годов на некоторых BSD, где shосновывался на оболочке Almquist ( testвстроенный всегда был включен в ashисходный код, но в тех BSD был изначально отключен)).

Обратите внимание на то, что testaka [- это команда для выполнения «тестов», для этой команды нет присваивания, поэтому нет причин для разногласий между оператором присваивания и равенства, поэтому оператор равенства равен =. ==поддерживается только несколькими недавними реализациями [(и является просто псевдонимом для =).

Поскольку [это не что иное, как команда, она обрабатывается оболочкой так же, как и любая другая команда.

В частности, в вашем примере, $aпоскольку он не заключен в кавычки, он будет разбит на несколько слов в соответствии с обычными правилами разделения слов, и каждое слово будет подвергаться генерации имени файла, иначе говоря, в результате будет возможно большее количество слов, каждое из этих слов приведет к отдельный аргумент для [команды.

Аналогично, z*будет расширен список имен файлов в текущем каталоге, начиная с z.

Так, например, если $aесть b* = x, и есть z1, z2, b1и b2файлы в текущем каталоге, то [команда получит 9 аргументов: [, b1, b2, =, x, ==, z1, z2и ].

[разбирает свои аргументы как условное выражение. Эти 9 аргументов не складываются в допустимое условное выражение, поэтому оно, вероятно, вернет ошибку.

[[ ... ]]Конструкция была введена Korn оболочки , вероятно , около 1988 , как ksh86aв 1987 году его не было в то время как ksh88было это с самого начала.

Помимо ksh (все реализации), [[...]]также поддерживается bash (начиная с версии 2.02) и zsh, но все три реализации различны и существуют различия между каждой версией одной и той же оболочки, хотя изменения, как правило, обратно совместимы (заметным исключением является bash =~оператор, который, как известно, ломал несколько скриптов после определенной версии, когда его поведение изменилось). [[...]]не указывается в POSIX, Unix или Linux (LSB). Он был рассмотрен для включения несколько раз, но не включен, так как его общая функциональность, поддерживаемая основными оболочками, уже описана [командой и case-in-esacконструкцией.

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

[[ ... ]]знает ==с самого начала и эквивалентно =1 . Ошибка ksh (хотя и вызывает путаницу и множество ошибок) заключается в том, что оператор =и ==не является оператором равенства, а оператором сопоставления с образцом (хотя аспект сопоставления можно отключить с помощью кавычек, но с неясными правилами, которые отличаются от оболочки к оболочке).

В приведенном выше коде [[ $a == z* ]]оболочка будет анализировать это на несколько токенов в правилах, похожих на обычные, распознавать их как сопоставление с образцом, рассматривать z*как образец для сопоставления с содержимым aпеременной.

Как правило, стрелять себе в ногу [[ ... ]]сложнее, чем [командой. Но несколько правил, таких как

  • всегда указывать переменные
  • никогда не используйте оператор -aor -o(используйте несколько [команд &&и операторы и || shell )

Сделайте [надежным с POSIX снарядами.

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

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


1 Исключение: [[...]]добавлено в bash в версии 2.02. До 2.03тех пор, пока это не будет изменено, [[ x = '?' ]]вернет true, а [[ x == '?' ]]вернет false. То есть цитирование не препятствовало сопоставлению с образцом при использовании =оператора в этих версиях, но было сделано при использовании ==.

Стефан Шазелас
источник
Отличная информация Не могли бы вы объяснить, почему «никогда не используйте оператор -a или -o»?
Гребнеке
@grebneke, попробуйте [ '!' = foo -o a = a ]в bash, например.
Стефан Шазелас
0

оба используются для оценки выражений, и [[не будет работать со старой оболочкой POSIX Bourn, а также [[также поддерживает сопоставление с образцом и регулярное выражение. пример попробуйте это

[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"

[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"

harish.venkat
источник
Обратите внимание, что оболочка Bourne не является POSIX, [[...]]поддерживает [регулярные выражения только в некоторых версиях некоторых оболочек, так же как некоторые версии поддерживают сопоставление регулярных выражений. Для сравнения, в тех оболочках, которые поддерживают [[, вы бы предпочли написать(( n == 0 && y == 0))
Стефан Шазелас