Разница между одиночными и двойными квадратными скобками в Bash
Я читаю примеры bash, if
только некоторые примеры написаны с помощью одиночных квадратных скобок:
if [ -f $param ]
then
#...
fi
другие с двойными квадратными скобками:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
В чем разница?
Ответы
Ответ 1
Одиночный []
- это тесты условий, совместимые с командами, совместимыми с командами.
Двойные [[]]
являются расширением стандарта []
и поддерживаются bash и другими оболочками (например, zsh, ksh). Они поддерживают дополнительные операции (а также стандартные операции posix). Например: ||
вместо -o
и соответствие регулярных выражений с помощью =~
. Более полный список различий можно найти в разделе bash в условных конструкциях.
Используйте []
, когда вы хотите, чтобы ваш script был переносимым через оболочки. Используйте [[]]
, если вы хотите, чтобы условные выражения не поддерживались []
и не нуждались в переносе.
Ответ 2
Различия в поведении
Протестировано в 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 ]
: синтаксическая ошибка, &&
анализируется как разделитель cmd1 && cmd2
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 ]
{ [ a = a ] || [ a = b ]; } && [ a = b ]
POSIX эквивалент 5
-
разделение слов и генерация имени файла при расширении (split + glob)
-
x='a b'; [[ $x = 'ab' ]]
x='a b'; [[ $x = 'ab' ]]
: правда, кавычки не нужны -
x='a b'; [ $x = 'ab' ]
x='a b'; [ $x = 'ab' ]
: синтаксическая ошибка, расширяется до [ ab = 'ab' ]
-
x='*'; [ $x = 'ab' ]
x='*'; [ $x = 'ab' ]
: синтаксическая ошибка, если в текущем каталоге более одного файла. -
x='a b'; [ "$x" = 'ab' ]
x='a b'; [ "$x" = 'ab' ]
: эквивалент POSIX
-
=
-
[[ ab = a? ]]
[[ ab = a? ]]
: true, потому что он выполняет сопоставление с образцом (*? [
являются волшебными). Не расширяется до файлов в текущем каталоге. -
[ ab = a? ]
[ ab = a? ]
: a?
шар расширяется. Так может быть true или false в зависимости от файлов в текущем каталоге. -
[ ab = a\? ]
[ ab = a\? ]
: ложно, не глобальное расширение -
=
и ==
одинаковы как в [
и в [[
, но ==
является расширением Bash. -
case ab in (a?) echo match; esac
case ab in (a?) echo match; esac
: POSIX эквивалент -
[[ ab =~ 'ab?' ]]
[[ ab =~ 'ab?' ]]
: false 4 теряет магию с ''
-
[[ ab? =~ 'ab?' ]]
[[ ab? =~ 'ab?' ]]
: правда
-
=~
-
[[ ab =~ ab? ]]
[[ ab =~ ab? ]]
: Верно, POSIX регулярное выражение матч, ?
не расширяется -
[ a =~ a ]
: синтаксическая ошибка. Нет эквивалента Bash. -
printf 'ab\n' | grep -Eq 'ab?'
: Эквивалент POSIX (только однострочные данные) -
awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
: POSIX эквивалент.
Рекомендация: всегда используйте []
.
Есть эквиваленты POSIX для каждой конструкции [[ ]]
которую я видел.
Если вы используете [[ ]]
вы:
- потерять мобильность
- заставьте читателя узнать тонкости другого расширения bash.
[
это обычная команда со странным именем, никакой особой семантики не требуется.
¹ Вдохновленный эквивалентной [[...]]
конструкцией в оболочке Корна
² но терпит неудачу для некоторых значений 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 ]
[ a = a ] || [ a = b ] && [ a = b ]
будет эквивалентно.
Ответ 3
Внутри отдельных скобок для теста условий (т.е. [...]) некоторые операторы, такие как одиночный =
, поддерживаются всеми оболочками, тогда как использование оператора ==
не поддерживается некоторыми из старых оболочек.
Внутри двойных скобок для теста условий (т.е. [[...]]) нет разницы между использованием =
или ==
в старых или новых оболочках.
Изменить: Следует также отметить, что: В bash всегда используйте двойные скобки [[...]], если это возможно, потому что это безопаснее, чем отдельные скобки. Я проиллюстрирую, почему в следующем примере:
if [ $var == "hello" ]; then
если $var имеет значение null/empty, то это то, что видит script:
if [ == "hello" ]; then
который сломает ваш script. Решение состоит в том, чтобы либо использовать двойные скобки, либо всегда помнить о том, чтобы помещать кавычки вокруг ваших переменных ("$var"
). Двойные скобки лучше защищают практику кодирования.
Ответ 4
[[
является ключевым словом bash, аналогичным (но более мощным, чем) [
команда.
Видеть
http://mywiki.wooledge.org/BashFAQ/031 и http://mywiki.wooledge.org/BashGuide/TestsAndConditionals
Если вы не пишете POSIX sh, мы рекомендуем [[
.
Ответ 5
вы можете использовать двойные квадратные скобки для соответствия регулярному выражению света, например.:
if [[ $1 =~ "foo.*bar" ]] ; then
(если версия bash, которую вы используете, поддерживает этот синтаксис)
Ответ 6
Bash руководство говорит:
При использовании с [[, < и ' > сортируют лексикографически используя текущий язык. Команда тестирования использует ASCII упорядочение.
(Команда тестирования идентична [])