В чем разница между двойными и одиночными квадратными скобками в bash?

Мне просто интересно, что именно разница между

[[ $STRING != foo ]]

и

[ $STRING != foo ]

, кроме того, последний является posix-совместимым, найденным в sh, а первый является расширением, найденным в bash.

322 голоса | спросил 0x89 10 AM00000010000005131 2009, 01:11:51

5 ответов


250

Есть несколько отличий. На мой взгляд, некоторые из наиболее важных:

  1. [ встроен в Bash и многие другие современные оболочки. Встроенный [ похож на test с дополнительным требованием закрытия ]. Встроенные [ и test) имитируют функциональные возможности /bin/[ и /bin/test) вместе с их ограничениями что скрипты будут обратно совместимы. Исходные исполняемые файлы по-прежнему существуют в основном для соответствия POSIX и обратной совместимости. Выполнение команды type [ в Bash означает, что [ интерпретируется как встроенный по умолчанию. (Примечание: which [ ищет только исполняемые файлы в PATH и эквивалентен типу type -p [)
  2. [[ не является совместимым, он обычно не будет работать с любыми пунктами /bin/sh). Таким образом, [[] - это более современный вариант Bash /Zsh /Ksh.
  3. Поскольку [[ встроен в оболочку и не имеет устаревших требований, вам не нужно беспокоиться о разбиении слов на основе переменной IFS ), чтобы испортить на переменные, которые оценивают строку с пробелами. Поэтому вам не нужно вставлять эту переменную в двойные кавычки.

По большей части, остальное - всего лишь несколько более симпатичный синтаксис. Чтобы увидеть больше различий, я рекомендую эту ссылку для ответа на часто задаваемые вопросы: В чем разница между тестом, [и [ ? . На самом деле, если вы серьезно относитесь к сценарию bash, я рекомендую прочитать всю wiki , включая FAQ, Ловушки и Руководство. Раздел теста из раздела руководства объясняет эти различия, а также почему автор (ы) думают, что [[] - лучший выбор, если вам не нужно беспокоиться о том, чтобы быть портативным. Основные причины:

  1. Вам не нужно беспокоиться о цитировании левой части теста, чтобы он действительно читался как переменная.
  2. Вам не нужно бежать меньше и больше < > с обратными косыми чертами, чтобы их не оценивали как входное перенаправление, что может действительно испортить некоторые вещи путем перезаписи файлов. Это снова возвращается к [[], являющемуся встроенным. Если [(test) является внешней программой, оболочка должна была бы сделать исключение в том, как она оценивает < и > только в том случае, если /bin/test, что на самом деле не имеет смысла.
ответил Kyle Brandt 10 AM00000010000000031 2009, 01:56:00
104

Вкратце:

  

[] - 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

ответил abhiomkar 29 WedEurope/Moscow2010-12-29T22:42:25+03:00Europe/Moscow12bEurope/MoscowWed, 29 Dec 2010 22:42:25 +0300 2010, 22:42:25
58

Различия в поведении

Протестировано в Bash 4.3.11:

  • POSIX vs Расширение 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 = a && b = b ]]: true, logical и
    • [ 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
  • разбиение слов

    • 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
  • =~

Рекомендация

Я предпочитаю всегда использовать [].

Существуют эквиваленты POSIX для каждой конструкции [[ ]], которую я видел.

Если вы используете [[ ]], вы:

  • потерять переносимость
  • заставляет читателя изучить тонкости другого расширения bash. [ - это просто регулярная команда со странным именем, никаких специальныхсемантика.
ответил Ciro Santilli 新疆改造中心 六四事件 法轮功 12 J000000Sunday15 2015, 13:22:47
4

Основываясь на быстром просмотре соответствующих разделов справочной страницы, основное отличие заключается в том, что операторы == и != соответствуют шаблону, а скорее чем буквальная строка, а также что существует оператор сравнения =~ regex.

ответил womble 10 AM00000010000005831 2009, 01:17:58
3

Одиночная скобка , т. е. [] - оболочка 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
ответил Premraj 8 FebruaryEurope/MoscowbMon, 08 Feb 2016 06:15:42 +0300000000amMon, 08 Feb 2016 06:15:42 +030016 2016, 06:15:42

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132