Являются ли двойные квадратные скобки [[]] предпочтительными в квадратных скобках [] в Bash?
Сотрудник недавно заявил в обзоре кода, что конструкция [[ ]]
должна быть предпочтительнее [ ]
в конструкциях типа
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
Он не мог объяснить. Есть один?
Ответы
Ответ 1
[[
имеет меньше неожиданностей и, как правило, безопаснее использовать. Но он не переносимый - POSIX не указывает, что он делает, и поддерживают его только некоторые оболочки (помимо bash, я слышал, что ksh поддерживает его). Например, вы можете сделать
[[ -e $b ]]
проверить, существует ли файл. Но с [
вы должны процитировать $b
, потому что он разделяет аргумент и расширяет такие вещи, как "a*"
(где [[
берет его буквально). Это также связано с тем, что [
может быть внешней программой и получает свой аргумент как обычно, как и любая другая программа (хотя она также может быть встроенной, но тогда она еще не имеет этой специальной обработки).
[[
также имеет некоторые другие приятные функции, такие как регулярное выражение, соответствующее =~
, а также такие операторы, как они известны на языках C-типа. Вот хорошая страница об этом: В чем разница между тестами, [
и [[
? и Bash Тесты
Ответ 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 ]
: синтаксическая ошибка, &&
анализируется как разделитель команд 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 для каждой конструкции [[ ]]
, которую я видел.
Если вы используете [[ ]]
, вы:
- потерять мобильность
- Заставьте читателя изучить тонкости другого расширения bash.
[
- это обычная команда со странным именем, никакой особой семантики здесь нет.
¹ 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.
Ответ 3
[[ ]]
имеет больше возможностей - я предлагаю вам ознакомиться с Advanced Bash Scripting Guide для получения дополнительной информации, в частности расширенная тестовая команда в Глава 7. Тесты.
Кстати, в качестве путеводителей, [[ ]]
был введен в ksh88 (версия версии Korn 1988 года).
Ответ 4
Какой компаратор, тест, скобка или двойная скобка являются самыми быстрыми? (http://bashcurescancer.com)
Двойная скобка - это "составная команда", где в качестве теста и одиночная скобка являются встроенными в оболочку (и на самом деле это одна и та же команда). Таким образом, одиночная скобка и двойная скобка выполняют разные коды.
Тест и одиночная скобка являются наиболее переносимыми, поскольку существуют как отдельные, так и внешние команды. Однако, если вы используете какую-либо удаленно современную версию BASH, двойная скобка поддерживается.
Ответ 5
Типичная ситуация, когда вы не можете использовать [[находится в autotools configure.ac script), там скобки имеют особое и другое значение, поэтому вам нужно будет использовать test
вместо [или [[- Примечание этот тест и [являются одной и той же программой.
Ответ 6
Если вам нравится следующее руководство по стилю 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
Ответ 7
[[]] двойные скобки не поддерживаются при определенной версии SunOS и полностью неавторизованных внутренних деклараций функций:
GNU bash, версия 2.02.0 (1) -release (sparc-sun-solaris2.6)
Ответ 8
В двух словах, [[лучше, потому что он не развивает другой процесс. Никакие скобки или одна скобка не являются более медленными, чем двойная скобка, потому что она вызывает еще один процесс.