Являются ли двойные квадратные скобки [[]] предпочтительнее одиночных квадратных скобок [] в Bash? - PullRequest
457 голосов
/ 21 марта 2009

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

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

Он не мог предоставить обоснование. Есть ли один?

Ответы [ 7 ]

518 голосов
/ 21 марта 2009

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

[[ -e $b ]]

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

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

75 голосов

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

Некоторые отличия в Bash 4.3.11:

  • 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 = 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 эквивалент⁵
  • разбиение слов и генерация имени файла при расширениях (split + glob)

    • x='a b'; [[ $x = 'a b' ]]: правда, кавычки не нужны
    • 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? шар расширяется. Так что может быть true или false в зависимости от файлов в текущем каталоге.
    • [ ab = a\? ]: ложь, не глобальное расширение
    • = и == одинаковы в [ и [[, но == является расширением Bash.
    • case ab in (a?) echo match; esac: эквивалент POSIX
    • [[ ab =~ 'ab?' ]]: ложь⁴, теряет магию с ''
    • [[ ab? =~ 'ab?' ]]: правда
  • =~

    • [[ ab =~ ab? ]]: true, POSIX расширенное регулярное выражение match, ? не расширяется
    • [ a =~ a ]: синтаксическая ошибка. Нет эквивалента Bash.
    • printf 'ab\n' | grep -Eq 'ab?': эквивалент POSIX (только однострочные данные)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': эквивалент POSIX.

Рекомендация : всегда используйте [].

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

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

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

¹ Вдохновленный эквивалентной [[...]] конструкцией в оболочке Korn

², но не для некоторых значений a или b (например, + или index) и выполняет числовое сравнение, если a и b выглядят как десятичные целые числа. expr "x$a" '<' "x$b" работает вокруг обоих.

³, а также не работает для некоторых значений a или b, таких как ! или (.

⁴ в bash 3.2 и выше и при условии, что совместимость с bash 3.1 не включена (как с BASH_COMPAT=3.1)

⁵ хотя группирование (здесь с группой команд {...;} вместо (...), которая запускает ненужную подоболочку) не является необходимым, поскольку операторы оболочки || и && (в отличие от операторов оболочки Операторы || и && [[...]] или операторы -o / -a [ имеют одинаковый приоритет. Так что [ a = a ] || [ a = b ] && [ a = b ] будет эквивалентно.

52 голосов
/ 21 марта 2009

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

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

8 голосов
/ 21 марта 2009

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

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

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

1 голос
/ 21 марта 2015

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

0 голосов
/ 19 марта 2013

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

0 голосов
/ 24 ноября 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...