Сотрудник недавно заявил в обзоре кода, что конструкция [[ ]] должна быть предпочтительнее [ ] в конструкциях типа
if [ "`id -nu`" = "$someuser" ] ; then 
     echo "I love you madly, $someuser"
fi
Он не мог объяснить. Есть один?
Сотрудник недавно заявил в обзоре кода, что конструкция [[ ]] должна быть предпочтительнее [ ] в конструкциях типа
if [ "`id -nu`" = "$someuser" ] ; then 
     echo "I love you madly, $someuser"
fi
Он не мог объяснить. Есть один?
 [[ имеет меньше неожиданностей и, как правило, безопаснее использовать. Но он не переносимый - POSIX не указывает, что он делает, и поддерживают его только некоторые оболочки (помимо bash, я слышал, что ksh поддерживает его). Например, вы можете сделать
[[ -e $b ]]
проверить, существует ли файл. Но с [ вы должны процитировать $b, потому что он разделяет аргумент и расширяет такие вещи, как "a*" (где [[ берет его буквально). Это также связано с тем, что [ может быть внешней программой и получает свой аргумент как обычно, как и любая другая программа (хотя она также может быть встроенной, но тогда она еще не имеет этой специальной обработки).
 [[ также имеет некоторые другие приятные функции, такие как регулярное выражение, соответствующее =~, а также такие операторы, как они известны на языках C-типа. Вот хорошая страница об этом: В чем разница между тестами, [ и [[? и  Bash Тесты
Различия в поведении
Некоторые отличия в 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 < b ]]: лексикографическое сравнение[ a \< b ]: то же, что и выше. \ требуется или же делает перенаправление как для любой другой команды. Расширение Bash.expr a \< b > /dev/null: эквивалент POSIX², см.: Как проверить строки на лексикографическое значение, меньшее или равное в Bash?&& и ||
[[ 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-эквивалент⁵разделение слов и генерация имени файла при расширениях (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?' ]]: false⁴, теряет магию с ''[[ ab? =~ 'ab?' ]]: правда=~
[[ ab =~ ab? ]]: истина, расширенное регулярное выражение POSIX extended regular expression соответствует, ? не расширяется[ a =~ a ]: синтаксическая ошибка. Нет эквивалента Bash.printf 'ab\n' | grep -Eq 'ab?': эквивалент POSIX (только однострочные данные)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': эквивалент POSIX.Рекомендация: всегда используйте [].
Есть эквиваленты POSIX для каждой конструкции [[ ]], которую я видел.
Если вы используете [[ ]], вы:
[ - это обычная команда со странным именем, никакой особой семантики здесь нет.¹ Inspired from the equivalent [TG471] construct in the Korn shell
² but fails for some values of [TG472] or [TG473] (like [TG474] or [TG475]) and does numeric comparison if [TG476] and [TG477] look like decimal integers. [TG478] works around both.
³ and also fails for some values of [TG479] or [TG480] like [TG481] or [TG482].
⁴ in bash 3.2 and above and provided compatibility to bash 3.1 is not enabled (like with [TG483])
⁵ though the grouping (here with the [TG484] command group instead of [TG485] which would run an unnecessary subshell) is not necessary as the [TG486] and [TG487] shell operators (as opposed to the [TG488] and [TG489] [TG490] operators or the [TG491]/[TG492] [TG493] operators) have equal precedence. So [TG494] would be equivalent.
 [[ ]] имеет больше возможностей - я предлагаю вам ознакомиться с Advanced Bash Scripting Guide для получения дополнительной информации, в частности расширенная тестовая команда в Глава 7. Тесты.
Кстати, в качестве путеводителей, [[ ]] был введен в ksh88 (версия версии Korn 1988 года).
Какой компаратор, тест, скобка или двойная скобка являются самыми быстрыми? (http://bashcurescancer.com)
Двойная скобка - это "составная команда", где в качестве теста и одиночная скобка являются встроенными в оболочку (и на самом деле это одна и та же команда). Таким образом, одиночная скобка и двойная скобка выполняют разные коды.
Тест и одиночная скобка являются наиболее переносимыми, поскольку существуют как отдельные, так и внешние команды. Однако, если вы используете какую-либо удаленно современную версию BASH, двойная скобка поддерживается.
Типичная ситуация, когда вы не можете использовать [[находится в autotools configure.ac script), там скобки имеют особое и другое значение, поэтому вам нужно будет использовать test вместо [или [[- Примечание этот тест и [являются одной и той же программой.
Если вам нравится следующее руководство по стилю Google:
Тест, [и [[
[[...]] уменьшает количество ошибок, так как между [[и]] и [[...]] не происходит расширения имени пути или разбиения слов, что позволяет сопоставлять регулярные выражения там, где [...] нет.
# This ensures the string on the left is made up of characters in the
# alnum character class followed by the string name.
# Note that the RHS should not be quoted here.
# For the gory details, see
# E14 at https://tiswww.case.edu/php/chet/bash/FAQ
if [[ "filename" =~ ^[[:alnum:]]+name ]]; then
  echo "Match"
fi
# This matches the exact pattern "f*" (Does not match in this case)
if [[ "filename" == "f*" ]]; then
  echo "Match"
fi
# This gives a "too many arguments" error as f* is expanded to the
# contents of the current directory
if [ "filename" == f* ]; then
  echo "Match"
fi
[[]] двойные скобки не поддерживаются при определенной версии SunOS и полностью неавторизованных внутренних деклараций функций: GNU bash, версия 2.02.0 (1) -release (sparc-sun-solaris2.6)
В двух словах, [[лучше, потому что он не развивает другой процесс. Никакие скобки или одна скобка не являются более медленными, чем двойная скобка, потому что она вызывает еще один процесс.