Разница между одинарными и двойными квадратными скобками в Bash

Я читаю примеры Bash о if но некоторые примеры написаны в квадратных скобках:

if [ -f $param ]
then
  #...
fi

другие с двойными квадратными скобками:

if [[ $? -ne 0 ]]
then
    start looking for errors in yourlog
fi

В чем разница?

7 ответов

Решение

Не замужем [] являются послегарантийными испытаниями состояния оболочки.

двойной [[]] являются расширением стандарта [] и поддерживаются bash и другими оболочками (например, zsh, ksh). Они поддерживают дополнительные операции (а также стандартные операции posix). Например: || вместо -o и регулярное выражение, совпадающее с =~, Более полный список различий можно найти в разделе руководства bash по условным конструкциям.

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

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

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

  • Расширение POSIX против Bash:

  • обычная команда против магии

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

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

      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.
    • Я не мог найти альтернативу POSIX этому, см.: Как проверить строки на меньше или равно?
  • && а также ||

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

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

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

Есть POSIX-эквиваленты для каждого [[ ]] построить я видел

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

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

[[ это ключевое слово bash, похожее на (но более мощное, чем) [ команда.

Увидеть

http://mywiki.wooledge.org/BashFAQ/031 и http://mywiki.wooledge.org/BashGuide/TestsAndConditionals

Если вы не пишете для POSIX sh, мы рекомендуем [[,

Внутри одинарных скобок для проверки условий (т. Е. [ ... ]), некоторые операторы, такие как одиночные = поддерживается всеми оболочками, тогда как использование оператора == не поддерживается некоторыми из более старых оболочек.

Внутри двойных скобок для проверки условий (т. Е. [[ ... ]]) нет разницы между использованием = или же == в старых или новых оболочках.

Изменить: Я также должен отметить, что: В bash всегда используйте двойные скобки [[...]], если это возможно, потому что это безопаснее, чем одиночные скобки. Я поясню почему на следующем примере:

if [ $var == "hello" ]; then

если $var оказывается пустым / пустым, то это то, что видит скрипт:

if [ == "hello" ]; then

который сломает ваш сценарий. Решение состоит в том, чтобы либо использовать двойные скобки, либо всегда не забывать заключать в кавычки переменные"$var"). Двойные скобки лучше защитной практики кодирования.

  • это builtinкак printf. Синтаксис Bash ожидает увидеть его там же, где и команды. А также ]для Bash ничего не значит, кроме того факта, что этого ожидает встроенный. (man bash / ВСТРОЕННЫЕ КОМАНДЫ ОБОЛОЧКИ)
  • это keywordкак если бы. Синтаксис Bash запускается также в том же месте, что и команда, но вместо выполнения он входит в условный контекст. А также ]]также является ключевым словом, заканчивающим этот контекст. (man bash / SHELL GRAMMAR / Составные команды)

По порядку bash пытается разобрать: Ключевые слова синтаксиса> Псевдоним пользователя> Встроенная функция> Пользовательская функция> Команда в $PATH

      type [  # [ is a shell builtin
type [[  # [[ is a shell keyword
type ]  # bash: type: ]: not found
type ]]  # ]] is a shell keyword
compgen -k  # Keywords: if then else ...
compgen -b  # Builtins: . : [ alias bg bind ...
which [  # /usr/bin/[
  • [медленнее <= он выполняет больше кода синтаксического анализа, я думаю. Но я знаю, что он вызывает такое же количество системных вызовов (проверено с
  • синтаксически легче анализировать даже человеку, поскольку он запускает контекст. Для арифметического условия подумайте об использовании ((.
      time for i in {1..1000000}; do [ 'a' = 'b' ] ; done  # 1.990s
time for i in {1..1000000}; do [[ 'a' == 'b' ]] ; done  # 1.371s

time for i in {1..1000000}; do if [ 'a' = 'a' ]; then if [ 'a' = 'b' ];then :; fi; fi ; done  # 3.512s
time for i in {1..1000000}; do if [[ 'a' == 'a' ]]; then if [[ 'a' == 'b' ]];then :; fi; fi; done  # 2.143s

strace -cf  bash -c "for i in {1..100000}; do if [ 'a' = 'a' ]; then if [ 'a' = 'b' ];then :; fi; fi  ; done;"  # 399
strace -cf  bash -c "for i in {1..100000}; do if [[ 'a' == 'a' ]]; then if [[ 'a' == 'b' ]];then :; fi; fi  ; done;"  # 399

Я рекомендую использовать [[: Если вы явно не заботитесь о совместимости с posix, это означает, что это не так, поэтому не беспокойтесь о том, чтобы получить "более" совместимый сценарий, который не является совместимым.

Вы можете использовать двойные квадратные скобки для сопоставления регулярных выражений, например:

if [[ $1 =~ "foo.*bar" ]] ; then

(если версия bash, которую вы используете, поддерживает этот синтаксис)

Руководство Bash говорит:

При использовании с [[, операторы '<' и '>' сортируют лексикографически с использованием текущей локали. Тестовая команда использует порядок ASCII.

(Тестовая команда идентична [ ])

Другие вопросы по тегам