в чем разница между двойными и одинарными квадратными скобками в bash?

<p>мне просто интересно, какая именно разница между</p><pre><code>[[ $string != foo ]] а также[ $string != foo ] </code></pre><p>кроме того, что последний является posix-совместимым, встречается в sh, а первый является расширением, найденным в bash.</p>

<p>есть несколько отличий. на мой взгляд, некоторые из наиболее важных являются:</p><ol> <li><code>[</code> является встроенным в bash и многих других современных оболочках. встроенный <code>[</code> похож на <code>test</code> с дополнительным требованием закрытия <code>]</code>. встроенные <code>[</code> и <code>test</code> имитируют функциональность <code>/bin/[</code> а также <code>/bin/test</code> вместе с их ограничениями, чтобы скрипты были обратно совместимы. оригинальные исполняемые файлы все еще существуют в основном для соответствия posix и обратной совместимости. выполнение команды <code>type [</code> в bash означает, что <code>[</code> по умолчанию интерпретируется как встроенный. (запись: <code>which [</code> ищет только исполняемые файлы по пути <em> [~ # ~] [~ # ~] </em> и эквивалентно <code>type -p [</code>)</li> <li><code>[[</code> не так совместимо, оно не обязательно будет работать с любым <code>/bin/sh</code> указывает на. так <code>[[</code> является более современной опцией bash/zsh/ksh.</li> <li>потому что <code>[[</code> встроен в оболочку и не имеет устаревших требований, вам не нужно беспокоиться о разбиении word на основе <em> [~ # ~] ifs [~ # ~] </em> переменная, чтобы связываться с переменными, которые оцениваются в строку с пробелами. следовательно, вам не нужно помещать переменную в двойные кавычки.</li> </ol><p>по большей части, остальное - просто более приятный синтаксис. чтобы увидеть больше различий, я рекомендую эту ссылку на ответ faq: <a href="http://mywiki.wooledge.org/bashfaq/031">в чем разница между test, [и [[?</a> . на самом деле, если вы серьезно) о сценариях bash я рекомендую прочитать все <a href="http://mywiki.wooledge.org/">wiki</a> , включая faq, <a href="http://mywiki.wooledge.org/bashpitfalls">pitfalls</a> и guide. <a href="http://mywiki.wooledge.org/bashguide/testsandconditionals#conditional\_blocks\_.28if.2c\_test\_and\_.5b.5b.29">раздел теста из раздела guide</a> объясняет эти различия, а также, почему автор (ы) думают <code>[[</code> будет лучшим выбором, если вам не нужно беспокоиться о своей портативности. основными причинами являются:</p><ol> <li>вам не нужно беспокоиться о цитировании левой части теста, чтобы он действительно читался как переменная.</li> <li>вам не нужно убегать меньше и больше, чем <code>< ></code> с обратными слешами, чтобы они не оценивались как перенаправление ввода, что может привести к путанице при перезаписи файлов. это снова восходит к <code>[[</code> будучи встроенным. если [(test) - внешняя программа, shell должна была бы сделать исключение в способе оценки <code><</code> а также <code>></code> только если <code>/bin/test</code> называется, что не имеет смысла.</li> </ol>

<p>короче говоря:</p><blockquote> <p>[это bash <strong> встроенный </strong></p> <p>[[]] ключевые слова bash <strong> </strong></p> </blockquote><p><strong> ключевые слова: </strong> ключевые слова очень похожи на встроенные, но основное отличие заключается в том, что к ним применяются специальные правила синтаксического анализа. например, [встроена в bash, а [[является ключевым словом bash. они оба используются для тестирования, но, поскольку [[является ключевым словом, а не встроенным, оно имеет несколько специальных правил синтаксического анализа, которые делают его намного проще:</p><pre><code> $ [ a < b ] -bash: b: no such file or directory $ [[ a < b ]] </code></pre><p>первый пример возвращает ошибку, потому что bash пытается перенаправить файл b в команду [a]. второй пример на самом деле делает то, что вы ожидаете. символ <больше не имеет специального значения оператора перенаправления файлов.</p><p>источник: <a href="http://mywiki.wooledge.org/bashguide/commandsandarguments">http://mywiki.wooledge.org/bashguide/commandsandarguments</a> </p>

<p><strong> различия в поведении </strong></p><p>некоторые отличия в bash 4.3.11:</p><ul> <li> <p>расширение posix против bash:</p> <ul> <li><code>[</code> <a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html">это posix</a> </li> <li><code>[[</code> - это расширение bash¹, задокументированное по адресу: <a href="https://www.gnu.org/software/bash/manual/bash.html#conditional-constructs">https://www.gnu.org/software/bash/manual/bash.html#conditional-constructs</a> </li> </ul> </li> <li> <p>обычная команда против магии</p> <ul> <li> <p><code>[</code> - это обычная команда со странным именем.</p> <p><code>]</code> - это просто аргумент <code>[</code>, который не позволяет использовать дополнительные аргументы.</p> <p>ubuntu 16.04 на самом деле имеет исполняемый файл для него по адресу <code>/usr/bin/[</code>, предоставляемый coreutils, но встроенная версия bash имеет преимущество.</p> <p>ничто не изменяется в том, как bash анализирует команду.</p> <p>в частности, <code><</code> - это перенаправление, <code>&&</code> и <code>||</code> объединяют несколько команд, <code>( )</code> генерирует субоболочки, если не выполняется <code>\</code>, а расширение word происходит как обычно.</p> </li> <li> <p><code>[[ x ]]</code> - это одиночная конструкция, которая позволяет магически анализировать <code>x</code>. <code><</code>, <code>&&</code>, <code>||</code> и <code>()</code> обрабатываются специально, и правила разбиения word отличаются.</p> <p>есть и другие отличия, такие как <code>=</code> и <code>=~</code>.</p> <p>в bashese: <code>[</code> - это встроенная команда, а <code>[[</code> - ключевое слово: <a href="https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword">https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword</a> </p> </li> </ul> </li> <li> <p><code><</code></p> <ul> <li><code>[[ a < b ]]</code>: лексикографическое сравнение</li> <li><code>[ a \< b ]</code>: то же, что и выше. требуется <code>\</code>, иначе перенаправление выполняется как для любой другой команды. расширение bash.</li> <li><code>expr a \< b > /dev/null</code>: posix-эквивалент², см .: <a href="https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989">https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989</a> </li> </ul> </li> <li> <p><code>&&</code> и <code>||</code></p> <ul> <li><code>[[ a = a && b = b ]]</code>: истина, логика <em> и</em></li> <li><code>[ a = a && b = b ]</code>: синтаксическая ошибка, <code>&&</code> анализируется как разделитель команд and <code>cmd1 && cmd2</code></li> <li><code>[ a = a -a b = b ]</code>: эквивалентно, но не поддерживается posix³</li> <li><code>[ a = a ] && [ b = b ]</code>: posix и надежный эквивалент</li> </ul> </li> <li> <p><code>(</code></p> <ul> <li><code>[[ (a = a || a = b) && a = b ]]</code>: false</li> <li><code>[ ( a = a ) ]</code>: синтаксическая ошибка, <code>()</code> интерпретируется как подоболочка</li> <li><code>[ \( a = a -o a = b \) -a a = b ]</code>: эквивалентно, но <code>()</code> устарел в posix</li> <li><code>{ [ a = a ] || [ a = b ]; } && [ a = b ]</code> posix эквивалент<sup>5</sup></li> </ul> </li> <li> <p>разделение слов и генерация имени файла при расширениях (split + glob)</p> <ul> <li><code>x='a b'; [[ $x = 'a b' ]]: true, кавычки не нужны x='a b'; [ $x = 'a b' ]</code>: синтаксическая ошибка, расширяется до <code>[ a b = 'a b' ]</code></li> <li><code>x='*'; [ $x = 'a b' ]: синтаксическая ошибка, если в текущем каталоге более одного файла. x='a b'; [ "$x" = 'a b' ]</code>: posix-эквивалент</li> </ul> </li> <li> <p><code>=</code></p> <ul> <li><code>[[ ab = a? ]]</code>: true, потому что это так <a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/v3\_chap02.html#tag\_18\_13">сопоставление с образцом</a> (<code>* ? [</code> - это волшебство). не расширяется до файлов в текущем каталоге.</li> <li><code>[ ab = a? ]</code>: <code>a?</code> glob расширяется. так может быть истина или ложь в зависимости от файлов в текущем каталоге.</li> <li><code>[ ab = a\? ]</code>: false, не глобальное расширение</li> <li><code>=</code> и <code>==</code> одинаковы как в <code>[</code>, так и в <code>[[</code>, но <code>==</code> является расширением bash.</li> <li><code>case ab in (a?) echo match; esac</code>: posix-эквивалент</li> <li><code>[[ ab =~ 'ab?' ]]</code>: false<sup>4</sup>, теряет магию с <code>''</code></li> <li><code>[[ ab? =~ 'ab?' ]]</code>: true</li> </ul> </li> <li> <p><code>=~</code></p> <ul> <li><code>[[ ab =~ ab? ]]</code>: true, posix <a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/v1\_chap09.html#tag\_09\_04">расширенное регулярное выражение</a> соответствует, <code>?</code> не расширяется</li> <li><code>[ a =~ a ]</code>: синтаксическая ошибка. нет эквивалента bash.</li> <li><code>printf 'ab\n' | grep -eq 'ab?'</code>: posix-эквивалент (только однострочные данные)</li> <li><code>awk 'begin{exit !(argv[1] ~ argv[2])}' ab 'ab?'</code>: posix-эквивалент.</li> </ul> </li> </ul><p><strong> рекомендация </strong>: всегда используйте <code>[]</code>.</p><p>есть posix-эквиваленты для каждой конструкции <code>[[ ]]</code>, которую я видел.</p><p>если вы используете <code>[[ ]]</code>, вы:</p><ul> <li>потерять мобильность</li> <li>заставьте читателя изучить тонкости другого расширения bash. <code>[</code> - это обычная команда со странным именем, никакой особой семантики не требуется.</li> </ul><hr><p><sup>¹ вдохновленный эквивалентной конструкцией <code>[[...]]</code> в korn shell</sup></p><p><sup>², но не для некоторых значений <code>a</code> или <code>b</code> (например, <code>+</code> или <code>index</code>) и выполняет числовое сравнение, если <code>a</code> и <code>b</code> выглядят как десятичные целые числа. <code>expr "x$a" '<' "x$b"</code> работает вокруг обоих.</sup></p><p><sup>³, а также завершается ошибкой для некоторых значений <code>a</code> или <code>b</code>, таких как <code>!</code> или <code>(</code>.</sup></p><p><sup><sup>4</sup> в bash 3.2 и выше и при условии, что совместимость с bash 3.1 не включена (как с <code>bash\_compat=3.1</code>)</sup></p><p><sup><sup>5</sup> хотя группировка (здесь с командой группой <code>{...;}</code> вместо <code>(...)</code> который должен пройти ненужную подоболочку) не является необходимым, как <code>||</code> и <code>&&</code> операторы shell (в отличие от <code>||</code> и <code>&&</code> операторов <code>[[...]]</code> или <code>-o</code>/<code>-a</code> <code>[</code> операторы) имеет равный старшинство. так что <code>[ a = a ] || [ a = b ] && [ a = b ]</code> будет эквивалентен.</sup></p>

<p><strong>одна скобка</strong> т.е. <code>[]</code> соответствует posix shell для включения условного выражения.</p><p><strong>двойные скобки</strong> т.е. <code>[[]]</code> является улучшенной (или расширенной) версией стандартной версии posix, это поддерживается bash и другими оболочками (zsh, ksh).</p><p>в bash для числового сравнения мы используем <code>eq</code>, <code>ne</code>, <code>lt</code> и <code>gt</code>, с двойными скобками для сравнения мы можем использовать <code>==</code>, <code>!=</code>, <code><,</code> а также <code>></code> буквально.</p><ul> <li><code>[</code> является синонимом команды test. даже если он встроен в оболочку, он создает новый процесс.</li> <li><code>[[</code> - это новая улучшенная версия, которая является ключевым словом, а не программой.</li> </ul><p>например:</p><pre><code>[ var1 lt var2] #works [ var1 < var2] #error: var2 no such file or directory [ var1 \< var2] #works with escape [[ var1 < var2]] #works </code></pre>

<p>основываясь на быстром чтении соответствующих разделов справочной страницы, основное различие заключается в том, что <code>==</code> а также <code>!=</code> операторы сопоставляются с шаблоном, а не с литеральной строкой, а также с наличием <code>=~</code> оператор сравнения регулярных выражений.</p>