Предпочтительнее ли двойные квадратные скобки []] над одиночными квадратными скобками [] в Bash?

сотрудник заявил недавно в обзоре кода, что [[ ]] конструкция должна быть предпочтительнее [ ] в конструкции типа

if [ "`id -nu`" = "$someuser" ] ; then 
     echo "I love you madly, $someuser"
fi

он не мог дать разумного объяснения. Есть такой?

7 ответов


[[ меньше сюрпризов и, как правило, безопаснее использовать. Но это не портативный-POSIX не указывает, что он делает, и только некоторые оболочки поддерживают его (рядом с bash, я слышал, что ksh тоже поддерживает его). Например, вы можете сделать

[[ -e $b ]]

чтобы проверить, существует ли файл. Но с [, вы должны цитировать $b, потому что он разбивает аргумент и расширяет такие вещи, как "a*" (где [[ занимает она в буквальном смысле). Это также связано с тем, как [ может быть внешним программа и получает свой аргумент так же нормально, как и любая другая программа (хотя она также может быть встроенной, но тогда она все еще не имеет этой специальной обработки).

[[ также имеет некоторые другие приятные функции, такие как регулярное выражение, соответствующее =~ вместе с операторами, как они известны в C-подобных языках. Вот хорошая страница об этом:в чем разница между тестом,[ и [[ ? и Bash Тесты


[[ ]] больше возможностей - я предлагаю вам взглянуть на Расширенный Bash Руководство Сценариев для получения дополнительной информации, в частности расширенный вариант команды test на Глава 7. Тесты.

кстати, как отмечает руководство, [[ ]] был представлен в ksh88 (версия 1988 оболочки Korn).


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

во-первых, давайте проанализируем различия в поведении обоих. Испытано в Bash 4.3.11.

  • расширение POSIX vs Bash:

    • [ это POSIX
    • [[ является расширением Bash
  • обычная команда против магии

    • [ - Это просто обычная команда со странным имя.

      ] - это просто аргумент [ Это предотвращает использование дополнительных аргументов.

      Ubuntu 16.04 на самом деле имеет исполняемый файл для него в /usr/bin/[ предоставлено coreutils, но встроенная версия bash имеет приоритет.

      ничего не изменяется в том, как Bash анализирует команду.

      в частности, < перенаправление, && и || объединить несколько команд ( ) генерирует подэлементы, если не экранирован by \, и расширение слова происходит, как обычно.

    • [[ X ]] - это одна конструкция, которая делает X волшебно разбирается. <, &&, || и () обрабатываются специально, и правила разделения слов различны.

      есть также дополнительные различия, такие как = и =~.

    В Bashese: [ является встроенной командой, и [[ - ключевое слово: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

    • [[ a < b ]]: лексикографическое сравнение
    • [ a \< b ]: то же, что и выше. \ требуется или делает перенаправление, как для любой другой команды. Расширение Баш.
    • я не мог найти альтернативу POSIX для этого, см.:Как проверить строки меньше или равны?
  • && и ||

    • [[ 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 ]]: false
    • [ ( a = a ) ]: синтаксическая ошибка,() интерпретируется как subshell
    • [ \( a = a -o a = b \) -a a = b ]: эквивалент, но () устарел POSIX
    • ([ a = a ] || [ a = b ]) && [ a = b ] рекомендация POSIX
  • разбиение

    • x='a b'; [[ $x = 'a b' ]]: правда, кавычки не нужны
    • x='a b'; [ $x = 'a b' ]: синтаксическая ошибка, расширяется до [ a b = 'a b' ]
    • x='a b'; [ "$x" = 'a b' ]: эквивалент
  • =

    • [[ ab = a? ]]: верно, потому что это шаблоны (* ? [ волшебные). Не glob расширяется до файлов в текущем каталоге.
    • [ ab = a? ]: a? Глоб расширяется. Так может быть true или false в зависимости от файлов в текущем каталоге.
    • [ ab = a\? ]: false, не расширение glob
    • = и == одинаковы в обоих [ и [[, а == является расширением Bash.
    • printf 'ab' | grep -Eq 'a.': POSIX ERE эквивалент
    • [[ ab =~ 'ab?' ]]: false, теряет магию с ''
    • [[ ab? =~ 'ab?' ]]: правда
  • =~

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

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

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

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

  • потерять мобильность
  • заставьте читателя изучить тонкости другого расширения bash. [ - Это обычная команда со странным именем, без специальной семантики вовлеченный.

с который компаратор, тест, кронштейн, или двойной кронштейн, самый быстрый? (http://bashcurescancer.com)

двойной кронштейн представляет собой " соединение команда " где как тест и одиночный кронштейн встроенные раковины (и внутри действительность - та же команда). Таким образом, одиночный кронштейн и двойной кронштейн выполнить другой код.

тест и одиночный кронштейн большинство портативных как они существуют как отдельный и внешняя команда. Однако, если вы используете любой удаленно современная версия BASH, the double кронштейн поддержан.


типичная ситуация, когда вы не можете использовать [[ в Autotools configure.AC script, там скобки имеют особое и другое значение, поэтому вам придется использовать test вместо [ или [[ -- обратите внимание, что test и [- одна и та же программа.


[[ ]] двойные скобки не указаны в определенной версии SunOS и полностью не указаны в объявлениях функций : GNU bash, версия 2.02.0 (1)-release (sparc-sun-solaris2.6)


в двух словах, [[лучше, потому что это не вилка другого процесса. Никакие кронштейны или один кронштейн не медленнее, чем двойной кронштейн, потому что он развивает другой процесс.