В чем разница между двойными и одиночными квадратными скобками в bash?
Мне просто интересно, что именно разница между
[[ $STRING != foo ]]
и
[ $STRING != foo ]
, кроме того, последний является posix-совместимым, найденным в sh, а первый является расширением, найденным в bash.
5 ответов
Есть несколько отличий. На мой взгляд, некоторые из наиболее важных:
-
[
встроен в Bash и многие другие современные оболочки. Встроенный[
похож наtest
с дополнительным требованием закрытия]
. Встроенные[
иtest
) имитируют функциональные возможности/bin/[
и/bin/test
) вместе с их ограничениями что скрипты будут обратно совместимы. Исходные исполняемые файлы по-прежнему существуют в основном для соответствия POSIX и обратной совместимости. Выполнение командыtype [
в Bash означает, что[
интерпретируется как встроенный по умолчанию. (Примечание:which [
ищет только исполняемые файлы в PATH и эквивалентен типуtype -p [
) -
[[
не является совместимым, он обычно не будет работать с любыми пунктами/bin/sh
). Таким образом,[[
] - это более современный вариант Bash /Zsh /Ksh. - Поскольку
[[
встроен в оболочку и не имеет устаревших требований, вам не нужно беспокоиться о разбиении слов на основе переменной IFS ), чтобы испортить на переменные, которые оценивают строку с пробелами. Поэтому вам не нужно вставлять эту переменную в двойные кавычки.
По большей части, остальное - всего лишь несколько более симпатичный синтаксис. Чтобы увидеть больше различий, я рекомендую эту ссылку для ответа на часто задаваемые вопросы: В чем разница между тестом, [и [ ? . На самом деле, если вы серьезно относитесь к сценарию bash, я рекомендую прочитать всю wiki , включая FAQ, Ловушки и Руководство. Раздел теста из раздела руководства объясняет эти различия, а также почему автор (ы) думают, что [[
] - лучший выбор, если вам не нужно беспокоиться о том, чтобы быть портативным. Основные причины:
- Вам не нужно беспокоиться о цитировании левой части теста, чтобы он действительно читался как переменная.
- Вам не нужно бежать меньше и больше
< >
с обратными косыми чертами, чтобы их не оценивали как входное перенаправление, что может действительно испортить некоторые вещи путем перезаписи файлов. Это снова возвращается к[[
], являющемуся встроенным. Если [(test) является внешней программой, оболочка должна была бы сделать исключение в том, как она оценивает<
и>
только в том случае, если/bin/test
, что на самом деле не имеет смысла.
Вкратце:
[] - bash Встроенные
[[]] являются bash Ключевые слова
Ключевые слова: Ключевые слова очень похожи на встроенные, но главное отличие в том, что к ним применяются специальные правила синтаксического анализа. Например, [является bash builtin, а [[является ключевым словом bash. Они оба используются для тестирования материала, но поскольку [[является ключевым словом, а не встроенным), это дает несколько особых правил синтаксического анализа, которые делают его намного проще:
$ [ a < b ]
-bash: b: No such file or directory
$ [[ a < b ]]
Первый пример возвращает ошибку, потому что bash пытается перенаправить файл b в команду [a]. Второй пример фактически делает то, что вы ожидаете от него. Символ <больше не имеет специального значения оператора перенаправления файлов.
Источник: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments
Различия в поведении
Протестировано в Bash 4.3.11:
-
POSIX vs Расширение Bash:
-
[
это POSIX -
[[
является расширением Bash
-
-
регулярная команда против магии
-
[
- просто регулярная команда со странным именем.]
- это просто аргумент[
, который предотвращает использование дополнительных аргументов.Ubuntu 16.04 фактически имеет исполняемый файл для него в
/usr/bin/[
, предоставленный coreutils, но встроенная версия bash имеет приоритет.Ничто не изменяется в том, как Bash анализирует команду.
В частности,
<
перенаправляется,&&
и||
объединяет несколько команд,( )
генерирует подоболочки, если не выполняется с помощью\
, а расширение слова происходит, как обычно. -
[[ X ]]
- это единственная конструкция, которая заставляетX
анализироваться магически.<
,&&
,||
и()
, и правила разделения слов отличается.Существуют и другие отличия, такие как
=
и=~
.
В Bashese:
[
- встроенная команда, а[[
] - это ключевое слово: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword -
-
<
-
[[ a < b ]]
: лексикографическое сравнение -
[ a \< b ]
: То же, что и выше.\
, либо перенаправление, как и для любой другой команды. Расширение Bash. - Я не мог найти альтернативу POSIX для этого: https://stackoverflow.com/questions/21294867/how-to-test-strings-for-less-than-or-equal
-
-
&&
и||
-
[[ a = a && b = b ]]
: true, logical и -
[ a = a && b = b ]
: синтаксическая ошибка,&&
анализируется как разделитель команды ANDcmd1 && cmd2
-
[ a = a -a b = b ]
: эквивалентно, но не рекомендуется POSIX -
[ a = a ] && [ b = b ]
: рекомендация POSIX
-
-
(
-
[[ (a = a || a = b) && a = b ]]
: false -
[ ( a = a ) ]
: синтаксическая ошибка,()
интерпретируется как подоболочка -
[ \( a = a -o a = b \) -a a = b ]
: эквивалентно, но()
устарел POSIX -
([ a = a ] || [ a = b ]) && [ a = b ]
Рекомендация POSIX
-
-
разбиение слов
-
x='a b'; [[ $x = 'a b' ]]
: true, кавычки не нужны -
x='a b'; [ $x = 'a b' ]
: синтаксическая ошибка, расширяется до[ a b = 'a b' ]
-
x='a b'; [ "$x" = 'a b' ]
: equal
-
-
=
-
[[ ab = a? ]]
: true, потому что он соответствие шаблонов (* ? [
являются магии). Не расширяет glob для файлов в текущем каталоге. -
[ ab = a? ]
:a?
расширяется. Так может быть правдой или ложью в зависимости от файлов в текущем каталоге. -
[ ab = a\? ]
: false, а не расширение glob -
=
и==
одинаковы как для[
, так и для[[
, но==
является расширением Bash. -
printf 'ab' | grep -Eq 'a.'
: эквивалент POSIX ERE -
[[ ab =~ 'ab?' ]]
: false, теряет магию с помощью''
-
[[ ab? =~ 'ab?' ]]
: true
-
-
=~
-
[[ ab =~ ab? ]]
: true, POSIX расширенное регулярное выражение match,?
не раскрывает glob -
[ a =~ a ]
: синтаксическая ошибка -
printf 'ab' | grep -Eq 'ab?'
: эквивалент POSIX
-
Рекомендация
Я предпочитаю всегда использовать []
.
Существуют эквиваленты POSIX для каждой конструкции [[ ]]
, которую я видел.
Если вы используете [[ ]]
, вы:
- потерять переносимость
- заставляет читателя изучить тонкости другого расширения bash.
[
- это просто регулярная команда со странным именем, никаких специальныхсемантика.
Основываясь на быстром просмотре соответствующих разделов справочной страницы, основное отличие заключается в том, что операторы ==
и !=
соответствуют шаблону, а скорее чем буквальная строка, а также что существует оператор сравнения =~
regex.
Одиночная скобка , т. е. []
- оболочка POSIX, соответствующая заключению условного выражения.
Двойные скобки , т. е. [[]]
- расширенная (или дополнительная) версия стандартной версии POSIX, это поддерживается bash и другими оболочками (zsh, ksh) .
В bash для численного сравнения мы используем eq
, ne
, lt
и gt
, с двойными скобками для сравнения мы можем использовать ==
, !=
, <,
и >
буквально.
-
[
является синонимом команды test. Даже если он встроен в оболочку, он создает новый процесс. -
[[
] - новая улучшенная версия, которая является ключевым словом, а не программой.
, например:
[ var1 lt var2] #works
[ var1 < var2] #error: var2 No such file or directory
[ var1 \< var2] #works with escape
[[ var1 < var2]] #works