Сотрудник недавно заявил в обзоре кода, что [[ ]]
конструкция должна быть более предпочтительной, чем [ ]
конструкции, подобные
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
Он не мог предоставить обоснование. Есть один?
bash
if-statement
syntax
Леонард
источник
источник
[[
с ним код хорошо и понятно, но помните тот день , когда вы будете порт ваших scriptworks по системе с оболочкой по умолчанию , который не являетсяbash
илиksh
, и т. д.[
уродливее, громоздче, но работает какAK-47
в любой ситуации.Ответы:
[[
имеет меньше сюрпризов и, как правило, безопаснее в использовании. Но он не переносим - POSIX не указывает, что он делает, и только некоторые оболочки поддерживают его (кроме bash, я слышал, что ksh тоже это поддерживает). Например, вы можете сделатьпроверить, существует ли файл. Но с
[
, вы должны цитировать$b
, потому что это разделяет аргумент и расширяет такие вещи, как"a*"
(где[[
буквально). Это также связано с тем, как[
может быть внешняя программа и получать ее аргумент, как обычно, как и любая другая программа (хотя она также может быть встроенной, но тогда она по-прежнему не имеет этой специальной обработки).[[
также имеет некоторые другие полезные функции, такие как сопоставление регулярных выражений с=~
операторами, как они известны в C-подобных языках. Вот хорошая страница об этом: В чем разница между тестом[
и[[
? и Баш тестыисточник
[[ ]]
но интерпретирует его так же, как и[ ]
.#!/bin/sh
но затем переключаю их на использование,#!/bin/bash
как только полагаюсь на какую-то особенность BASH, чтобы обозначить, что она больше не является переносимой оболочкой Bourne.Различия в поведении
Некоторые отличия в Bash 4.3.11:
Расширение POSIX против Bash:
[
это POSIX[[
такое расширение Bash ¹обычная команда против магии
[
это обычная команда со странным именем.]
это просто аргумент,[
который не позволяет использовать другие аргументы.Ubuntu 16.04 на самом деле имеет исполняемый файл для него,
/usr/bin/[
предоставляемый coreutils , но встроенная версия bash имеет преимущество.Ничто не изменяется в том, как Bash анализирует команду.
В частности,
<
происходит перенаправление&&
и||
объединение нескольких команд,( )
генерируются подоболочки, если не выполняется экранирование\
, и расширение слов происходит как обычно.[[ X ]]
это единственная конструкция, которая делаетX
быть разобранным магическим образом.<
,&&
,||
И()
рассматриваются специально, и правила разбиения на слова различны.Есть и другие отличия, как
=
и=~
.В Bashese:
[
это встроенная команда и[[
ключевое слово: /ubuntu/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 ]
: синтаксическая ошибка,&&
проанализированная как разделитель команд 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 эквивалент⁵разделение слов и генерация имени файла при расширениях (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? ]]
: true, потому что он выполняет сопоставление с образцом (* ? [
это волшебство). Не расширяется до файлов в текущем каталоге.[ ab = a? ]
:a?
glob расширяется. Так может быть истина или ложь в зависимости от файлов в текущем каталоге.[ ab = a\? ]
: false, не глобальное расширение=
и==
одинаковы в обоих[
и[[
, но==
это расширение Bash.case ab in (a?) echo match; esac
: POSIX эквивалент[[ ab =~ 'ab?' ]]
: false⁴, теряет магию с''
[[ ab? =~ 'ab?' ]]
: правда=~
[[ ab =~ ab? ]]
: true, POSIX расширенное совпадение с регулярным выражением ,?
не расширяется[ a =~ a ]
: ошибка синтаксиса. Нет эквивалента Bash.printf 'ab\n' | grep -Eq 'ab?'
: Эквивалент POSIX (только однострочные данные)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
: POSIX эквивалент.Рекомендация : всегда используйте
[]
.Есть POSIX-эквиваленты для каждой
[[ ]]
конструкции, которую я видел.Если вы используете
[[ ]]
вас:[
это обычная команда со странным именем, никакой особой семантики не требуется.¹ Вдохновленный эквивалентной
[[...]]
конструкции в оболочке Korn² но терпит неудачу для некоторых значений
a
илиb
(например,+
илиindex
) и выполняет числовое сравнение, еслиa
иb
выглядит как десятичные целые числа.expr "x$a" '<' "x$b"
работает вокруг обоих.³, а также терпит неудачу для некоторых значений
a
илиb
как!
или(
.⁴ в bash 3.2 и выше и при условии, что совместимость с bash 3.1 не включена (как с
BASH_COMPAT=3.1
)⁵ хотя группировка (здесь с
{...;}
командой группой вместо(...)
которой будет работать ненужную подоболочку) не является необходимым , как||
и&&
оболочками операторов (в отличие от||
и&&
[[...]]
операторов или-o
/-a
[
операторов) имеет одинаковый приоритет. Так[ a = a ] || [ a = b ] && [ a = b ]
было бы эквивалентно.источник
[
по тем же причинам.[[ ]]
имеет больше возможностей - я предлагаю вам взглянуть на Advanced Bash Scripting Guide для получения дополнительной информации, в частности, на расширенный раздел команды test в Главе 7. Тесты .Кстати, как отмечается в руководстве, он
[[ ]]
был введен в ksh88 (версия оболочки Korn 1988 года).источник
От Which компаратора, тест, кронштейн или двойной кронштейн, является самым быстрым? ( http://bashcurescancer.com )
источник
[[
может принести улучшение . Но тогда я старый пердун старой школы :-)[
иtest
даже хотя внешние варианты существуют.PS1=...crazy stuff...
и / или$PROMPT_COMMAND
); для них я не хочу заметной задержки в выполнении сценария.apt-get update
если прошло больше X часов с момента последнего запуска. Это большое облегчение, когда можно оставить переносимость в уже слишком длинном списке ограничений для кода.Если вам нравится следующее руководство по стилю Google :
Тест
[
и[[
источник
[[ -d ~ ]]
возвращает true (что подразумевает~
расширение до/home/user
). Я думаю, что Google должен был быть более точным в своем письме.Типичная ситуация, когда вы не можете использовать
[[
это в скрипте autotools configure.ac, где скобки имеют особое и другое значение, поэтому вам придется использоватьtest
вместо[
или[[
- Обратите внимание, что тестируют и[
являются одной и той же программой.источник
[
что их определят как функцию оболочки POSIX?[[]] двойные скобки не поддерживаются в определенной версии SunOS и полностью не поддерживаются внутри объявлений функций: GNU bash, версия 2.02.0 (1) -релиз (sparc-sun-solaris2.6)
источник
Короче говоря, [[лучше, потому что он не разворачивает другой процесс. Никакие скобки или одиночные скобки медленнее, чем двойные, потому что они разветвляются на другой процесс.
источник
type [
чтобы увидеть это.[[
, в отличие от[
синтаксиса, интерпретируется интерпретатором командной строки bash. В bash попробуйте набратьtype [[
. Unix4linux правильно, что хотя классические[
тесты Bourne-shell запускают новый процесс для определения значения истинности,[[
синтаксис (заимствованный из ksh посредством bash, zsh и т. д.) - нет.[
она встроена в Bash и Dash (/bin/sh
во всех дистрибутивах Linux, производных от Debian).