Мне просто интересно, какая именно разница между
[[ $STRING != foo ]]
а также
[ $STRING != foo ]
кроме того, что последний является posix-совместимым, встречается в sh, а первый является расширением, найденным в bash.
Есть несколько отличий. На мой взгляд, некоторые из наиболее важных являются:
[
является встроенным в Bash и многих других современных оболочках. Встроенный [
похож на test
с дополнительным требованием закрытия ]
. Встроенные [
и test
имитируют функциональность /bin/[
а также /bin/test
вместе с их ограничениями, чтобы скрипты были обратно совместимы. Оригинальные исполняемые файлы все еще существуют в основном для соответствия POSIX и обратной совместимости. Выполнение команды type [
в Bash означает, что [
по умолчанию интерпретируется как встроенный. (Запись: which [
ищет только исполняемые файлы по пути [~ # ~] [~ # ~] и эквивалентно type -p [
)[[
не так совместимо, оно не обязательно будет работать с любым /bin/sh
указывает на. Так [[
является более современной опцией Bash/Zsh/Ksh.[[
встроен в оболочку и не имеет устаревших требований, вам не нужно беспокоиться о разбиении Word на основе [~ # ~] ifs [~ # ~] переменная, чтобы связываться с переменными, которые оцениваются в строку с пробелами. Следовательно, вам не нужно помещать переменную в двойные кавычки.По большей части, остальное - просто более приятный синтаксис. Чтобы увидеть больше различий, я рекомендую эту ссылку на ответ FAQ: В чем разница между test, [и [[? . На самом деле, если вы серьезно) о сценариях bash я рекомендую прочитать все wiki , включая FAQ, Pitfalls и Guide. раздел теста из раздела guide объясняет эти различия, а также, почему автор (ы) думают [[
будет лучшим выбором, если вам не нужно беспокоиться о своей портативности. Основными причинами являются:
< >
с обратными слешами, чтобы они не оценивались как перенаправление ввода, что может привести к путанице при перезаписи файлов. Это снова восходит к [[
будучи встроенным. Если [(test) - внешняя программа, Shell должна была бы сделать исключение в способе оценки <
а также >
только если /bin/test
называется, что не имеет смысла.Короче говоря:
[это bash Встроенный
[[]] ключевые слова 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 анализирует команду.
В частности, <
- это перенаправление, &&
и ||
объединяют несколько команд, ( )
генерирует субоболочки, если не выполняется \
, а расширение Word происходит как обычно.
[[ X ]]
- это одиночная конструкция, которая позволяет магически анализировать X
. <
, &&
, ||
и ()
обрабатываются специально, и правила разбиения Word отличаются.
Есть и другие отличия, такие как =
и =~
.
В Bashese: [
- это встроенная команда, а [[
- ключевое слово: 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 ]
: синтаксическая ошибка, &&
анализируется как разделитель команд AND cmd1 && 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 эквивалент5Разделение слов и генерация имени файла при расширениях (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? ]]
: true, потому что это так сопоставление с образцом (* ? [
- это волшебство). Не расширяется до файлов в текущем каталоге.[ ab = a? ]
: a?
glob расширяется. Так может быть истина или ложь в зависимости от файлов в текущем каталоге.[ ab = a\? ]
: false, не глобальное расширение=
и ==
одинаковы как в [
, так и в [[
, но ==
является расширением Bash.case ab in (a?) echo match; esac
: POSIX-эквивалент[[ ab =~ 'ab?' ]]
: false4, теряет магию с ''
[[ ab? =~ 'ab?' ]]
: true=~
[[ ab =~ ab? ]]
: true, POSIX расширенное регулярное выражение соответствует, ?
не расширяется[ a =~ a ]
: синтаксическая ошибка. Нет эквивалента Bash.printf 'ab\n' | grep -Eq 'ab?'
: POSIX-эквивалент (только однострочные данные)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
: POSIX-эквивалент. Рекомендация : всегда используйте []
.
Есть POSIX-эквиваленты для каждой конструкции [[ ]]
, которую я видел.
Если вы используете [[ ]]
, вы:
[
- это обычная команда со странным именем, никакой особой семантики не требуется.¹ Вдохновленный эквивалентной конструкцией [[...]]
в Korn Shell
², но не для некоторых значений a
или b
(например, +
или index
) и выполняет числовое сравнение, если a
и b
выглядят как десятичные целые числа. expr "x$a" '<' "x$b"
работает вокруг обоих.
³, а также завершается ошибкой для некоторых значений a
или b
, таких как !
или (
.
4 в bash 3.2 и выше и при условии, что совместимость с bash 3.1 не включена (как с BASH_COMPAT=3.1
)
5 хотя группировка (здесь с командой группой {...;}
вместо (...)
который должен пройти ненужную подоболочку) не является необходимым, как ||
и &&
операторы Shell (в отличие от ||
и &&
операторов [[...]]
или -o
/-a
[
операторы) имеет равный старшинство. Так что [ a = a ] || [ a = b ] && [ a = b ]
будет эквивалентен.
одна скобка т.е. []
соответствует POSIX Shell для включения условного выражения.
двойные скобки т.е. [[]]
является улучшенной (или расширенной) версией стандартной версии 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
Основываясь на быстром чтении соответствующих разделов справочной страницы, основное различие заключается в том, что ==
а также !=
операторы сопоставляются с шаблоном, а не с литеральной строкой, а также с наличием =~
оператор сравнения регулярных выражений.