Какая разница между [и [[в Bash?

Я просмотрел справочную страницу bash, а [[ говорит, что использует условные выражения. Затем я просмотрел раздел "Условные выражения" и перечисляет те же операторы, что и test[).

Так интересно, в чем разница между [ и [[ в Bash?

Ответ 1

[[ является bash улучшением команды [. Он имеет несколько улучшений, которые делают его лучшим выбором, если вы пишете скрипты, предназначенные для bash. Мои фавориты:

  • Это синтаксическая особенность оболочки, поэтому она имеет какое-то особое поведение, которое [ не имеет. Вам больше не нужно указывать переменные вроде mad, потому что [[ обрабатывает пустые строки и строки с пробелами более интуитивно. Например, при [ вам нужно написать

    if [ -f "$file" ]
    

    чтобы правильно обрабатывать пустые строки или имена файлов с пробелами в них. При [[ цитаты не нужны:

    if [[ -f $file ]]
    
  • Поскольку это синтаксическая функция, она позволяет использовать операторы && и || для булевых тестов и < и > для сравнения строк. [ не может это сделать, потому что это регулярная команда, а &&, ||, < и > не передаются в обычные команды в качестве аргументов командной строки.

  • У этого есть замечательный оператор =~ для выполнения матчей регулярных выражений. С помощью [ вы можете написать

    if [ "$answer" = y -o "$answer" = yes ]
    

    С [[ вы можете записать это как

    if [[ $answer =~ ^y(es)?$ ]]
    

    Он даже позволяет вам получить доступ к захваченным группам, которые он хранит в BASH_REMATCH. Например, ${BASH_REMATCH[1]} будет "es", если вы набрали полное "да" выше.

  • Вы получаете бесплатную подборку шаблонов aka globbing. Может быть, вы менее строги в том, как вводить "да". Может быть, вы в порядке, если пользователь вводит y-anything. Покрывало:

    if [[ $ANSWER = y* ]]
    

Имейте в виду, что это расширение bash, поэтому, если вы пишете sh-совместимые скрипты, вам нужно придерживаться [. Убедитесь, что у вас есть #!/bin/bash строка shebang для вашего script, если вы используете двойные скобки.

См. также

Ответ 2

  • [ совпадает с встроенным test и работает как двоичный test (мужской тест)
    • работает примерно так же, как [ во всех других оболочках sh на многих UNIX-подобных средах.
    • поддерживает только одно условие. Несколько тестов с операторами bash && и || должны быть в отдельных скобках.
    • не поддерживает оператор 'not'. Чтобы инвертировать условие, используйте ! вне первой скобки, чтобы использовать средство оболочки для инвертирования значений возвращаемых команд.
    • == и != - литеральные сравнения строк
  • [[ является bash
    • bash -специфичен, хотя другие оболочки могут реализовывать аналогичные конструкции. Не ожидайте этого в старой школе UNIX sh.
    • == и != применять правила соответствия шаблону bash, см. "Согласование шаблонов" в man bash
    • имеет оператор соответствия =~ регулярных выражений
    • позволяет использовать круглые скобки и логические операторы !, && и || в скобках для объединения подвыражений

Кроме того, они довольно похожи - большинство отдельных тестов работают одинаково между ними, вещи становятся интересными только тогда, когда вам нужно комбинировать разные тесты с логическими операциями AND/OR/NOT.

Ответ 3

В bash, в отличие от [, [[ предотвращает разделение слов значений переменных.

Ответ 4

Самым важным отличием будет ясность вашего кода. Да, да, сказанное выше верно, но [[]] приводит ваш код в соответствие с тем, что вы ожидаете на языках высокого уровня, особенно в отношении AND (&&), OR (||) и NOT (!) операторы. Таким образом, когда вы перемещаетесь между системами и языками, вы сможете быстрее интерпретировать сценарий, что облегчает вашу жизнь. Получите подробности из хорошего справочника по UNIX/Linux. Вы можете найти некоторые мелочи полезными в определенных обстоятельствах, но вы всегда будете ценить ясный код! Какой фрагмент сценария вы бы предпочли прочитать? Даже вне контекста, первый выбор легче читать и понимать.


if [[ -d $newDir && -n $(echo $newDir | grep "^${webRootParent}") && -n $(echo $newDir | grep '/$') ]]; then ...

или же

if [ -d "$newDir" -a -n "$(echo "$newDir" | grep "^${webRootParent}")" -a -n "$(echo "$newDir" | grep '/$')" ]; then ...