Разница между одинарными и двойными квадратными скобками в 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:
[
это 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 ]
: ошибка синтаксиса,&&
анализируется как разделитель команд ANDcmd1 && 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?' ]]
: правда
=~
[[ ab =~ ab? ]]
: true, расширенное соответствие регулярного выражения POSIX,?
не расширяется[ a =~ a ]
: ошибка синтаксисаprintf 'ab' | grep -Eq 'ab?'
: POSIX эквивалент
Рекомендация
Я предпочитаю всегда использовать []
,
Есть 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.
(Тестовая команда идентична [ ])