Гид по технологиям

Условные тесты в Bash: [ ] и [[ ]] — подробное руководство

10 min read Bash Обновлено 26 Dec 2025
Условные тесты Bash: [ ] vs [[ ]]
Условные тесты Bash: [ ] vs [[ ]]

Двойные скобки [[ ]] в Bash дают более удобный и безопасный синтаксис для условных проверок: поддерживают globbing, регулярные выражения и логические операторы без необходимости экранирования/кавычек. Одинарные скобки [ ] и команда test совместимы с POSIX и работают в других шеллах, но требуют осторожности с пробелами, кавычками и подстановкой имён файлов. Выбирайте [[ ]] для скриптов, явно запускаемых в Bash; используйте [ ] для максимальной портируемости.

Быстрые ссылки

  • Single and Double Brackets
  • Builtins and Keywords
  • Shell Globbing
  • Quoting Strings
  • Filename Globbing Gotchas
  • Logical AND and OR
  • Regexes
  • Just One Condition

Условные тесты управляют ветвлением выполнения Bash-скриптов в зависимости от логического выражения. Двойные скобки упрощают синтаксис, но имеют свои подводные камни.

Single and Double Brackets

Bash обеспечивает команду test. Она позволяет проверять логические выражения. Выражение возвращает код выхода: 0 означает true, любое другое значение — false.

Цепочка команд в командной строке с помощью оператора && использует это поведение: следующая команда выполнится только если предыдущая завершилась успешно.

Если проверка истинна, слово “Yes” будет напечатано.

test 15 -eq 15 && echo "Yes"
test 14 -eq 15 && echo "Yes"

Одинарные скобки [ ] имитируют поведение команды test. Они оборачивают выражение в квадратные скобки и функционируют так же, как test. По сути это одна и та же программа, созданная из одного исходника. Единственное различие — обработка запросов помощи.

Из исходников видно, что поведение обработки опций отличается для формы test и для формы [ при отсутствии завершающей “]”.

/* Recognize --help or --version, but only when invoked in the

Форма “[“ при последнем аргументе, не равном “]”, обрабатывает –help/–version иначе, чем test.

Мы можем проверить это, запросив помощь у test и [ и посмотрев код возврата в Bash.

test --help
echo $?
[ --help
echo $?

Ноутбук с открытой командной строкой Linux на синем фоне.

Обе команды — test и [ — присутствуют в Bash как встроенные (builtins). Но также доступна и внешняя бинарная версия [.

type test
type [
whereis [

![Вывод команд, показывающий типы команд test и .

В отличие от этого, двойные скобки [[ и ]] — это ключевые слова (keywords). Они также выполняют логические проверки, но синтаксис у них иной. Так как это ключевые слова, внутри них доступны функции, которые не работают в форме с [ ].

Двойные скобки поддерживаются Bash (и некоторыми совместимыми шеллами), но не во всех. Например, Korn shell (ksh) поддерживает их, а sh — нет. Во всех примерах в статье скрипты начинаются с:

#!/bin/bash

Это гарантирует, что сценарий будет выполняться именно в Bash.

Builtins and Keywords

Список встроенных команд (builtins) можно получить через compgen:

compgen -b | fmt -w 70

(Без передачи через fmt строки будут в столбик; fmt группирует их в абзацы.)

Список встроенных команд Bash.

Мы увидим test и [ в этом списке, но одиночная “]” не отдельно. Команда [ ищет завершающую “]” чтобы понять конец выражения, но “]” не является отдельной встроенной командой.

Ключевые слова показаны так:

compgen -k | fmt -w 70

[[ и ]] — отдельные элементы в списке ключевых слов, поскольку [[ рассматривается как одно ключевое слово, а ]] — как другое. Они образуют парную конструкцию, как if/fi или case/esac.

Когда Bash парсит скрипт и встречает ключевое слово с парным закрывающим ключевым словом, он обрабатывает всё между ними особым образом.

С другой стороны, для builtin-команды все последующие аргументы передаются ей как параметры обычной команды, поэтому автор скрипта должен учитывать пробелы в значениях переменных и необходимость кавычек.

Shell Globbing

Двойные скобки поддерживают shell globbing. Это значит, что символ * будет расширяться как “любая последовательность символов”.

Скопируйте следующий текст в файл whelkie.sh:

#!/bin/bash

stringvar="Whelkie Brookes"

if [[ "$stringvar" == *elk* ]];
then
    echo "Warning contains seafood"
else
    echo "Free from molluscs"
fi

Сделайте скрипт исполняемым:

chmod +x whelkie.sh

При запуске скрипта строка “elk” найдена в “Whelkie”, несмотря на окружающие символы:

./whelkie.sh

Обратите внимание: если вы возьмёте шаблон в двойные кавычки (например “elk“), то globbing не произойдёт — шаблон будет рассматриваться буквально.

Другие формы globbing тоже поддерживаются: ? соответствует одному символу, а диапазоны внутри [] — набору символов. Например, чтобы покрыть оба варианта регистра:

#!/bin/bash

stringvar="Jean-Claude van Clam"

if [[ "$stringvar" == *[cC]lam* ]];
then
    echo "Warning contains seafood."
else
    echo "Free from molluscs."
fi

Сохраните как damme.sh, сделайте исполняемым и запустите.

Quoting Strings

Ранее мы упомянули, что обёртывание шаблонов в двойные кавычки отключает globbing. Тем не менее, при использовании [[ ]] нет строгой необходимости всегда брать в кавычки переменные, даже если они содержат пробелы — [[ ]] защищает от разбивания по пробелам в большинстве случаев.

Пример:

#!/bin/bash

stringvar="van Damme"
surname="van Damme"

if [[ $stringvar == $surname ]];
then
    echo "Surnames match."
else
    echo "Surnames don't match."
fi

Сохраните как surname.sh, сделайте исполняемым и запустите.

Даже с пробелами сравнение сработает. Это удобно при работе с путями и именами каталогов с пробелами. В частности, опция -d возвращает true, если переменная содержит существующий каталог:

#!/bin/bash

dir="/home/dave/Documents/Needs Work"

if [[ -d ${dir} ]];
then
    echo "Directory confirmed"
else
    echo "Directory not found"
fi

Измените путь на свой, сохраните как dir.sh, сделайте исполняемым и выполните.

Filename Globbing Gotchas

Различие между [ ] и [[ ]] проявляется при проверках, где участвуют шаблоны имён файлов. Шаблон “*.sh” совпадает со всеми скриптами. При использовании одинарных скобок [ ] поведение может вызвать ошибку, если шаблон разворачивается в несколько файлов: тогда неподходящее количество аргументов ломает проверку.

Пример с [ ]:

#!/bin/bash

if [ -a *.sh ];
then
    echo "Found a script file"
else
    echo "Didn't find a script file"
fi

Сохраните как script.sh и запустите в каталоге с несколькими .sh-файлами — Bash выбросит ошибку.

Если оставить только один скрипт (только один файл, соответствующий *.sh), проверка отработает.

Если же переписать скрипт на [[ ]]:

#!/bin/bash

if [[ -a *.sh ]];
then
    echo "Found a script file"
else
    echo "Didn't find a script file"
fi

и запустить в каталоге с множеством .sh-скриптов, ошибок не будет, но выражение, скорее всего, не найдёт файл, потому что внутри [[ ]] шаблон интерпретируется буквально, если он не разворачивается внешним шеллом.

Иначе говоря, [[ -a .sh ]] вернёт true лишь в том необычном случае, если в каталоге действительно есть файл с именем “.sh”.

Совет: для проверки наличия любого файла по маске используйте цикл или команду glob-обработки в оболочке, например:

shopt -s nullglob
files=( *.sh )
if (( ${#files[@]} )); then
    echo "Found a script file"
else
    echo "Didn't find a script file"
fi

Это надёжный и переносимый способ проверить наличие совпадающих файлов.

Logical AND and OR

Двойные скобки позволяют использовать && и || как логические операторы AND и OR внутри самого выражения.

Пример AND (оба условия должны быть истинны):

#!/bin/bash

first=10
second=25

if [[ $first -eq 10 && $second -lt 26 ]];
then
    echo "Condition met"
else
    echo "Condition failed"
fi

Сохраните как and.sh и запустите.

Пример OR (хотя бы одно условие истинно):

#!/bin/bash

first=10
second=25

if [[ $first -gt 15 || $second -lt 26 ]];
then
    echo "Condition met."
else
    echo "Condition failed."
fi

Сохраните как or.sh и запустите.

Важно: при использовании логических операторов внутри [[ ]] не забывайте про порядок операций и, при необходимости, группировку с помощью круглых скобок.

Regexes

[[ ]] поддерживают оператор =~, который применяет регулярное выражение (regex) к строковому выражению. Если regex удовлетворён — результат true.

Сохраните в regex.sh:

#!/bin/bash

words="one two three"

WordsandNumbers="one 1 two 2 three 3"

email="dave@fabricateddomain.co.uk"

mask1="[0-9]"

mask2="[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,4}"

if [[ $words =~ $mask1 ]];
then
    echo "\"$words\" contains digits."
else
    echo "No digits found in \"$words\"."
fi

if [[ $WordsandNumbers =~ $mask1 ]];
then
    echo "\"$WordsandNumbers\" contains digits."
else
    echo "No digits found in \"$WordsandNumbers\"."
fi

if [[ $email =~ $mask2 ]];
then
    echo "\"$email\" is a valid e-mail address."
else
    echo "Couldn't parse \"$email\"."
fi

Описание шаблона mask2:

  • [A-Za-z0-9.%+-]+ — одна или более букв, цифр или символов . % + -
  • @ — символ @
  • [A-Za-z0-9.-]+ — одна или более букв, цифр, точек или дефисов
  • . — точка
  • [A-Za-z]{2,4} — доменная часть из 2–4 букв

Этот regex достаточно прост и покрывает базовый формат e-mail, но не все возможные случаи (см. раздел “Когда это не работает”).

Запустив скрипт, вы увидите:

  • Первая проверка вернёт false — в words нет цифр.
  • Вторая — true — там есть цифры.
  • Третья — true — адрес соответствует простому шаблону.

Just One Condition

Двойные скобки делают проверки гибкими и более читаемыми. Возможность использовать regex в проверках — веская причина освоить [[ ]] в Bash-скриптах.

Просто убедитесь, что скрипт запускается в шелле, поддерживающем [[ ]], то есть в Bash.

Важно: если скрипт должен быть портируемым на sh, используйте POSIX-совместимые конструкции и избегайте [[ ]] или выполняйте проверку шелла перед исполнением.

Когда это не работает — типичные ошибки и случаи

  • Портируемость: /bin/sh может не поддерживать [[ ]]. Если ваш скрипт запускают в sh — поведение будет отличаться. Для совместимости используйте [ ] или test.
  • Regex: оператор =~ ведёт себя по-разному для разных версий Bash в части обработки кавычек и слэшей. Никогда не берите regex в кавычки при использовании =~, иначе он будет восприниматься буквально.
  • Globbing в [[ ]] может интерпретироваться иначе, чем вы ожидаете: шаблон внутри [[ ]] иногда не разворачивается так, как во внешнем контексте.
  • Имена переменных: забытые $ перед переменной (напр. if [[ first -eq 10 ]] вместо [[ $first -eq 10 ]]) сравнивают литералы, а не значения.
  • Специальные символы: при использовании расширенных регулярных выражений учитывайте, что некоторые символы нужно экранировать, и что поведение в Perl-совместимых regex отличается от POSIX ERE.

Альтернативные подходы и шаблоны проектирования

  • Для портируемости: используйте test/[ ] и аккуратно экранируйте пробелы. Это правильно при написании скриптов, которые должны работать в /bin/sh.
  • Для надёжной работы с группами файлов: включайте shopt -s nullglob и работайте с массивами для проверки наличия совпадающих файлов.
  • Если нужно сложное регулярное сопоставление: используйте external tools (grep -E, awk, sed, perl) и проверяйте их код возврата.
  • Для проверки пути используйте встроенные проверки -d, -f, -r и т. п. (они работают и в [ ] и в [[ ]]).

Ментальные модели и эвристики

  • “[[ ]] — это безопасный и расширенный режим Bash для проверок; [ ] — это POSIX-совместимый минимум.”
  • Используйте [[ ]] когда вы контролируете интерпретатор (#!/bin/bash).
  • Используйте [ ] или test, если скрипт должен выполняться в самых разных шеллах.
  • Для работы с файлами и шаблонами полагайтесь на возможность явной обработки glob-расширений (shopt/nullglob).

Быстрая таблица совместимости

КонструкцияПоддерживается в BashПоддерживается в shКомментарий
testдадаPOSIX-совместима
[ ]дадатребует закрывающую “]”
[[ ]]данетрасширенная, Bash-only
=~данетregex только в [[ ]]

Чеклист для разработчика / системного администратора

  • Скрипт начинается с #!/bin/bash, если используется []
  • Нет незамеченных шаблонов (*.sh) в [] проверках
  • Regex в =~ не заключён в кавычки
  • При работе с файлами использован nullglob/массивы, если ожидается несколько совпадений
  • Логические выражения явно сгруппированы (при необходимости)
  • Есть тесты/примерные входные данные для всех ветвей if

Мини-методология: как выбрать между [ ] и [[ ]]

  1. Определите требуемую портируемость. Если нужен sh — выбирайте [ ] или test.
  2. Если нужен удобный синтаксис, globbing и regex — используйте [[ ]].
  3. При использовании [[ ]] убедитесь, что shebang указывает на /bin/bash.
  4. Добавьте тесты/юнит-скрипты для критичных ветвей и edge-case-ов.

Тесты и критерии приёмки

  • Скрипт, использующий [[ ]] должен корректно выполняться при запуске через /bin/bash.
  • Проверяя наличие файлов по шаблону, ожидаемый результат должен совпадать с поведением реального каталога в CI (учтите nullglob).
  • Regex-проверки должны дать ожидаемые true/false на заранее подготовленных строках.

Примеры тест-кейсов

  • Проверка: переменная = “a b”; условие [[ $var == “a b” ]] должно вернуть true.
  • Проверка: каталог существует; if [[ -d $dir ]] должен вернуть true.
  • Проверка: шаблон *.sh при нескольких файлах: поведение скрипта с [ ] — ошибка, с nullglob+массивом — успешная проверка наличия.
  • Regex-проверка email: набор положительных и отрицательных примеров (валидные/невалидные адреса).

Runbook при проблемах

  1. Убедитесь, что shebang — #!/bin/bash.
  2. Запустите set -x для отладки: это покажет, как Bash расширяет переменные и шаблоны.
  3. Проверьте, не заключены ли шаблоны в кавычки (это отключит globbing).
  4. Для regex проверьте, не экранированы ли спецсимволы излишне.
  5. Если дело в файлах — включите shopt -s nullglob и вывод массива файлов для инспекции.

Безопасность и конфиденциальность

  • Никогда не подставляйте пользовательский ввод напрямую в команды без валидации; в условных проверках это может привести к неожиданным результатам.
  • Для парсинга и проверки внешних данных лучше применять строгие regex и дополнительные проверки, а не полагаться только на =~.

Альтернативы для локали и окружения

  • В окружениях с ограниченным набором шеллов (например, BusyBox sh) всегда используйте POSIX-совместимые конструкции.
  • Если нужно кросс-платформенное поведение (Linux и *BSD), тестируйте в CI на соответствующих образах.

Полезные сниппеты (cheat sheet)

  • Проверить существование файла:
if [ -f "$file" ]; then echo "file"; fi
  • Проверить существование каталога (Bash):
if [[ -d $dir ]]; then echo "dir exists"; fi
  • Нахождение совпадающих файлов без ошибки:
shopt -s nullglob
files=( *.sh )
if (( ${#files[@]} > 0 )); then echo "Found"; fi
  • Regex-проверка без кавычек:
if [[ $s =~ [0-9]{3}-[0-9]{2}-[0-9]{4} ]]; then echo "matched"; fi

Decision flow (Mermaid)

flowchart TD
    A[Начало: нужно условие в скрипте?]
    A --> B{Будет ли скрипт запускаться в /bin/bash?}
    B -- Да --> C[Используйте [[ ]] для удобства и regex]
    B -- Нет --> D[Используйте [ ] / test для портируемости]
    C --> E{Нужна проверка файлов по шаблону?}
    E -- Да --> F[Используйте nullglob + массивы или цикл]
    E -- Нет --> G[Обычные проверки -d, -f и т.п.]
    D --> G
    F --> H[Тесты в CI: проверьте каталоги с 0,1,>1 файлами]
    G --> H
    H --> I[Готово]

Короткое резюме

  • [[ ]] — расширенная, удобная и безопасная конструкция для Bash; поддерживает regex, логические операторы и упрощает работу с пробелами.
  • и test — POSIX-совместимые и подходят там, где важна переносимость.
  • Для проверки масок файлов используйте nullglob и массивы, чтобы избежать ошибок при развертывании шаблонов.

Ключевые выводы

  • Выбирайте конструкцию в зависимости от требуемой совместимости и возможностей окружения.
  • Тестируйте сценарии с разными наборами данных: пустыми, однозначными и множественными совпадениями.
  • Используйте set -x и shopt для локальной отладки и управления поведением расширений.

Спасибо за прочтение — используйте эти практики, чтобы скрипты были предсказуемыми и надёжными.

![Найденные типы команд test и

Запуск скрипта script.sh с ошибкой при множественных совпадениях

Результат выполнения dscript.sh, который ищет файл с именем

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как смотреть парад Macy's в День благодарения
Развлечения

Как смотреть парад Macy's в День благодарения

Настройка графики NVIDIA: Control Panel и GeForce Experience
Графика

Настройка графики NVIDIA: Control Panel и GeForce Experience

Как управлять LIFX с Windows
Умный дом

Как управлять LIFX с Windows

Добавить BlackArch в Arch Linux — быстрый гайд
Linux

Добавить BlackArch в Arch Linux — быстрый гайд

Добавление маркеров в Microsoft Word
Microsoft Word

Добавление маркеров в Microsoft Word

Установка приложений в Manjaro: 6 простых способов
Linux

Установка приложений в Manjaro: 6 простых способов