Мне просто интересно, в чем именно разница между
[[ $STRING != foo ]]
и
[ $STRING != foo ]
кроме того, последний является posix-совместимым, находится в sh, а первый является расширением, найденным в bash.
Есть несколько отличий. На мой взгляд, самые важные из них:
[
встроен в Bash и многие другие современные оболочки. Встроенный [
похоже на test
с дополнительным требованием закрытия ]
. Встроенные [
и test
имитировать функциональность /bin/[
и /bin/test
наряду с их ограничениями, чтобы скрипты были обратно совместимы. Исходные исполняемые файлы все еще существуют в основном для соответствия POSIX и обратной совместимости. Запуск команды type [
в Bash указывает, что [
по умолчанию интерпретируется как встроенный. (Заметка: which [
ищет только исполняемые файлы на ДОРОЖКА и эквивалентен type -p [
)[[
не так совместим, он не обязательно будет работать с любым /bin/sh
указывает на. Так [[
это более современный вариант Bash / Zsh / Ksh.[[
встроен в оболочку и не имеет устаревших требований, вам не нужно беспокоиться о разделении слов на основе IFS переменная, чтобы испортить переменные, которые оцениваются как строка с пробелами. Таким образом, вам действительно не нужно заключать переменную в двойные кавычки.По большей части остальное - просто более приятный синтаксис. Чтобы увидеть больше различий, я рекомендую эту ссылку на ответ на часто задаваемые вопросы: В чем разница между test, [и [[?. На самом деле, если вы серьезно относитесь к написанию сценариев bash, я рекомендую прочитать всю вики, включая FAQ, Ловушки, и Руководство. Тестовый раздел из раздела руководства также объясняет эти различия и почему автор (ы) думает [[
- лучший выбор, если вам не нужно беспокоиться о портативности. Основные причины:
< >
с обратной косой чертой, чтобы они не оценивались как перенаправление ввода, что может действительно испортить некоторые вещи, перезаписав файлы. Это снова возвращается к [[
будучи встроенным. Если [(test) - внешняя программа, оболочка должна будет сделать исключение в способе оценки. <
и >
только если /bin/test
вызывается, что на самом деле не имеет смысла.Коротко:
[это тупица Встроенный
[[]] - это bash Ключевые слова
Ключевые слова: Ключевые слова очень похожи на встроенные, но главное отличие в том, что к ним применяются специальные правила синтаксического анализа. Например, [- это встроенная функция bash, а [[- ключевое слово 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 против Bash:
[
это POSIX[[
является расширением Bash¹, документированным по адресу: https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructsобычная команда против магии
[
это просто обычная команда со странным названием.
]
это просто аргумент [
это предотвращает использование дальнейших аргументов.
В Ubuntu 16.04 есть исполняемый файл для него по адресу /usr/bin/[
предоставляется coreutils, но встроенная версия bash имеет приоритет.
В способе синтаксического анализа команды Bash ничего не меняется.
В частности, <
это перенаправление, &&
и ||
объединить несколько команд, ( )
генерирует подоболочки, если не экранируется \
, и расширение слова происходит как обычно.
[[ X ]]
это единственная конструкция, которая делает X
разбираться волшебным образом. <
, &&
, ||
и ()
обрабатываются особым образом, и правила разделения слов другие.
Есть и другие отличия, такие как =
и =~
.
В Башезе: [
это встроенная команда, и [[
это ключевое слово: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword
<
[[ a < b ]]
: лексикографическое сравнение[ a \< b ]
: То же, что и выше. \
требуется, иначе выполняет перенаправление, как и для любой другой команды. Расширение Bash.expr a \< b > /dev/null
: Эквивалент POSIX², см .: https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989&&
и ||
[[ a = a && b = b ]]
: правда, логично и[ a = a && b = b ]
: ошибка синтаксиса, &&
анализируется как разделитель команд И cmd1 && cmd2
[ a = a -a b = b ]
: эквивалентно, но устарело в POSIX³[ a = a ] && [ b = b ]
: POSIX и надежный эквивалент(
[[ (a = a || a = b) && a = b ]]
: ложный[ ( a = a ) ]
: ошибка синтаксиса, ()
интерпретируется как подоболочка[ \( a = a -o a = b \) -a a = b ]
: эквивалент, но ()
устарело POSIX{ [ a = a ] || [ a = b ]; } && [ a = b ]
Эквивалент POSIX5разбиение слов и генерация имени файла при расширении (split + glob)
x='a b'; [[ $x = 'a b' ]]
: true, кавычки не нужныx='a b'; [ $x = 'a b' ]
: синтаксическая ошибка, заменяется на [ a b = 'a b' ]
x='*'; [ $x = 'a b' ]
: синтаксическая ошибка, если в текущем каталоге больше одного файла.x='a b'; [ "$x" = 'a b' ]
: Эквивалент POSIX=
[[ ab = a? ]]
: правда, потому что это так сопоставление с образцом (* ? [
магические). Не расширяется до файлов в текущем каталоге.[ ab = a? ]
: a?
glob расширяется. Так может быть истина или ложь в зависимости от файлов в текущем каталоге.[ ab = a\? ]
: false, а не расширение глобуса=
и ==
одинаковы в обоих [
и [[
, но ==
это расширение Bash.case ab in (a?) echo match; esac
: Эквивалент POSIX[[ ab =~ 'ab?' ]]
: ложный4, теряет магию с ''
[[ ab? =~ 'ab?' ]]
: правда=~
[[ ab =~ ab? ]]
: правда, POSIX расширенное регулярное выражение соответствие, ?
не расширяется[ a =~ a ]
: ошибка синтаксиса. Нет эквивалента в bash.printf 'ab\n' | grep -Eq 'ab?'
: Эквивалент POSIX (только однострочные данные)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
: Эквивалент POSIX.Рекомендация: всегда используйте []
.
Есть эквиваленты POSIX для каждого [[ ]]
построить я видел.
Если вы используете [[ ]]
ты:
[
это просто обычная команда со странным именем, никакой специальной семантики здесь нет.¹ Вдохновленный аналогом [[...]]
построить в оболочке Korn
², но не работает для некоторых значений a
или b
(лайк +
или index
) и выполняет числовое сравнение, если a
и b
выглядят как десятичные целые числа. expr "x$a" '<' "x$b"
работает вокруг обоих.
³ и также не выполняется для некоторых значений a
или b
лайк !
или (
.
4 в bash 3.2 и выше и при условии, что совместимость с bash 3.1 не включена (например, с BASH_COMPAT=3.1
)
5 хотя группировка (здесь с {...;}
группа команд вместо (...)
который запустил бы ненужную подоболочку) не требуется, поскольку ||
и &&
операторы оболочки (в отличие от ||
и &&
[[...]]
операторы или -o
/-a
[
операторы) имеют равный приоритет. Так [ a = a ] || [ a = b ] && [ a = b ]
было бы эквивалентно.
Одиночный кронштейн т.е. []
совместима ли оболочка POSIX с условным выражением.
Двойные скобки т.е. [[]]
- это расширенная (или расширенная) версия стандартной версии POSIX, она поддерживается bash и другими оболочками (zsh, ksh).
В bash для числового сравнения мы используем eq
, ne
,lt
и gt
, с двойными скобками для сравнения мы можем использовать ==
, !=
, <,
и >
буквально.
[
является синонимом тестовой команды. Даже если он встроен в оболочку, он создает новый процесс.[[
это его новая улучшенная версия, которая является ключевым словом, а не программой. например:
[ var1 lt var2] #works
[ var1 < var2] #error: var2 No such file or directory
[ var1 \< var2] #works with escape
[[ var1 < var2]] #works
Основываясь на быстром чтении соответствующих разделов справочной страницы, основная разница заключается в том, что ==
и !=
операторы сопоставляются с шаблоном, а не с буквальной строкой, а также что есть =~
оператор сравнения регулярных выражений.