Ответы:
Разница между [[ … ]]
и [ … ]
в основном заключается в использовании одинарной или двойной скобки - bash . Важно то, что [[ … ]]
это специальный синтаксис, а [
название команды выглядит смешно. [[ … ]]
имеет специальные правила синтаксиса для того, что внутри, [ … ]
нет.
С добавлением морщины подстановочного знака, вот как [[ $a == z* ]]
оценивается:
[[ … ]]
условная конструкция вокруг условного выражения $a == z*
.==
бинарный оператор с операндами $a
и z*
.a
.==
оператор: проверьте, соответствует ли значение переменной a
шаблону z*
.Вот как [ $a == z* ]
это оценивается:
[
команда с аргументами , образуемых оценки слова $a
, ==
, z*
, ]
.$a
в значение переменной a
.a
является строка 6 символов foo b*
(полученная , например a='foo b*'
) , и список файлов в текущем каталоге ( bar
, baz
, qux
, zim
, zum
), то результат разложения является следующим списком слов: [
, foo
, bar
, baz
, ==
, zim
, zum
, ]
.[
с параметрами, полученными на предыдущем шаге.
[
команда жалуется на синтаксическую ошибку и возвращает статус 2.Примечание. На [[ $a == z* ]]
шаге 3 значение a
не подвергается разделению слов и генерации имени файла, поскольку оно находится в контексте, где ожидается одно слово (левый аргумент условного оператора ==
). В большинстве случаев, если в этой позиции имеет смысл одно слово, расширение переменной ведет себя так же, как в двойных кавычках. Однако из этого правила есть исключение: [[ abc == $a ]]
если значение a
содержит подстановочные знаки, то a
сопоставляется с шаблоном подстановочных знаков. Например, если значение a
равно true, a*
то [[ abc == $a ]]
это правда (потому что подстановочный знак, *
полученный при раскрытии $a
совпадений без кавычек *
), тогда [[ abc == "$a" ]]
как ложно (потому что обычный символ*
исходя из приведенного расширения $a
не совпадает bc
). Внутри [[ … ]]
, двойные кавычки не делают разницы, кроме как на правой стороне операторов строки соответствия ( =
, ==
, !=
и =~
).
[
это псевдоним для 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 был изначально отключен)).
Обратите внимание на то, что test
aka [
- это команда для выполнения «тестов», для этой команды нет присваивания, поэтому нет причин для разногласий между оператором присваивания и равенства, поэтому оператор равенства равен =
. ==
поддерживается только несколькими недавними реализациями [
(и является просто псевдонимом для =
).
Поскольку [
это не что иное, как команда, она обрабатывается оболочкой так же, как и любая другая команда.
В частности, в вашем примере, $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
переменной.
Как правило, стрелять себе в ногу [[ ... ]]
сложнее, чем [
командой. Но несколько правил, таких как
-a
or -o
(используйте несколько [
команд &&
и операторы и ||
shell )Сделайте [
надежным с POSIX снарядами.
[[...]]
в различных оболочках поддерживаются дополнительные операторы, такие как операторы -nt
сопоставления регулярных выражений ... но список и поведение варьируются от оболочки к оболочке и от версии к версии.
Так что, если вы не знаете, какая оболочка и какая у вас минимальная версия, когда-либо будет интерпретироваться вашим сценарием, вероятно, безопаснее придерживаться стандартной [
команды.
1 Исключение: [[...]]
добавлено в bash в версии 2.02
. До 2.03
тех пор, пока это не будет изменено, [[ x = '?' ]]
вернет true, а [[ x == '?' ]]
вернет false. То есть цитирование не препятствовало сопоставлению с образцом при использовании =
оператора в этих версиях, но было сделано при использовании ==
.
[ '!' = foo -o a = a ]
в bash
, например.
оба используются для оценки выражений, и [[не будет работать со старой оболочкой POSIX Bourn, а также [[также поддерживает сопоставление с образцом и регулярное выражение. пример попробуйте это
[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"
[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"
[[...]]
поддерживает [
регулярные выражения только в некоторых версиях некоторых оболочек, так же как некоторые версии поддерживают сопоставление регулярных выражений. Для сравнения, в тех оболочках, которые поддерживают [[
, вы бы предпочли написать(( n == 0 && y == 0))