НейроАгент

Полное руководство: проверка наличия подстроки в строке в Bash

Узнайте самые эффективные методы проверки наличия подстроки в строке в Bash. Сравните встроенные операторы, case-выражения, grep и подходы с регулярными выражениями с производительностью и лучшими практиками.

Вопрос

Как проверить, содержит ли строка подстроку в Bash

У меня есть строка в Bash:

bash
string="My string"

Как проверить, содержит ли она другую строку? Я пробовал использовать:

bash
if [ $string ?? 'foo' ]; then
  echo "It's there!"
fi

Где ?? - это мой неизвестный оператор. Правильно ли использовать echo и grep?

bash
if echo "$string" | grep 'foo'; then
  echo "It's there!"
fi

Это кажется немного громоздким. Какой правильный способ проверять наличие подстрок в Bash?

НейроАгент

Самый эффективный и распространенный способ проверить, содержит ли строка подстроку в Bash, — это использование оператора [[ с шаблонами с подстановочными знаками. Для вашего примера вы бы написали:

bash
string="Моя строка"
if [[ $string == *"foo"* ]]; then
  echo "Она там есть!"
fi

Этот метод встроен в Bash, не требует внешних команд и работает быстрее, чем использование grep.


Содержание


Встроенные методы Bash

Использование оператора [[ с подстановочными знаками

Наиболее прямой подход использует встроенное сопоставление шаблонов Bash с оператором [[:

bash
string="Моя строка"
substring="foo"

if [[ $string == *"$substring"* ]]; then
    echo "Подстрока найдена!"
else
    echo "Подстрока не найдена"
fi

Ключевые моменты:

  • Символы * действуют как подстановочные знаки, соответствующие любой последовательности символов
  • Всегда заключайте переменную подстроки в кавычки для правильной обработки специальных символов
  • Оператор [[ — это расширенная условная конструкция Bash

Использование оператора case

Оператор case предоставляет эффективную альтернативу:

bash
string="Моя строка"
substring="foo"

case $string in
    *"$substring"*)
        echo "Подстрока найдена!"
        ;;
    *)
        echo "Подстрока не найдена"
        ;;
esac

Как отмечается в обсуждении на Stack Overflow, метод с case на самом деле эффективнее оператора [[ для поиска подстрок.

Использование регулярных выражений

Bash поддерживает сопоставление с регулярными выражениями с помощью оператора =~:

bash
string="Моя строка"
substring="foo"

if [[ $string =~ .*"$substring".* ]]; then
    echo "Подстрока найдена!"
fi

Использование внешних команд

Метод с grep

Хотя ваш подход с grep работает, его можно оптимизировать:

bash
string="Моя строка"
substring="foo"

if echo "$string" | grep -q "$substring"; then
    echo "Подстрока найдена!"
fi

Опция -q делает grep тихим и возвращает только код завершения. Однако, как отмечено на Linuxize, этот метод менее эффективен, так как требует создания нового процесса.

Альтернатива с here-document

Вместо echo можно использовать here-document:

bash
if grep -q "$substring" <<< "$string"; then
    echo "Подстрока найдена!"
fi

Расширенное сопоставление шаблонов

Несколько подстрок

Можно проверить наличие нескольких подстрок с помощью логических операторов:

bash
string="Привет мир"
if [[ $string == *"Привет"* && $string == *"мир"* ]]; then
    echo "Обе подстроки найдены!"
fi

Варианты шаблонов

Различные шаблоны с подстановочными знаками для разных нужд:

bash
# Начинается с подстроки
if [[ $string == "foo"* ]]; then
    echo "Строка начинается с 'foo'"
fi

# Заканчивается подстрокой
if [[ $string == *"foo" ]]; then
    echo "Строка заканчивается на 'foo'"
fi

# Точное положение (не напрямую, но с помощью regex)
if [[ $string =~ foo ]]; then
    echo "Содержит 'foo'"
fi

Сопоставление без учета регистра

Использование grep с флагом игнорирования регистра

bash
string="Привет Мир"
substring="привет"

if echo "$string" | grep -qi "$substring"; then
    echo "Подстрока найдена (без учета регистра)!"
fi

Использование shopt для сопоставления без учета регистра в Bash

bash
shopt -s nocasematch
string="Привет Мир"
substring="привет"

if [[ $string == *"привет"* ]]; then
    echo "Подстрока найдена (без учета регистра)!"
fi
shopt -u nocasematch  # Выключить сопоставление без учета регистра

Сравнение производительности

На основе результатов исследований, вот как методы сравниваются по производительности:

  1. Оператор case - наиболее эффективный, особенно для больших строк
  2. Оператор [[ с подстановочными знаками - хорошая производительность, очень читаемый
  3. Регулярные выражения (=~) - более мощные, но медленнее, чем сопоставление шаблонов
  4. Метод с grep - наименее эффективный из-за накладных расходов на создание процесса

Как упоминается в ответе на Stack Overflow, обновление 2023 года подтвердило, что метод с case значительно эффективнее подходов с расширением параметров.


Лучшие практики

Всегда заключайте переменные в кавычки

bash
# Хорошо
if [[ "$string" == *"foo"* ]]; then

# Плохо (может вызвать проблемы с пробелами или специальными символами)
if [[ $string == *foo* ]]; then

Обработка пустых строк

bash
if [[ -n "$string" && "$string" == *"foo"* ]]; then
    echo "Непустая строка содержит 'foo'"
fi

Используйте [[ вместо [

Оператор [[ более мощный и безопаснее, чем старая команда теста [:

bash
# Лучше
if [[ $string == *"foo"* ]]; then

# Старый стиль, более ограниченный
if [ "$string" = *foo* ]; then  # Это не будет работать с подстановочными знаками!

Учитывайте переносимость

Если вашему скрипту нужно работать в средах без Bash (например, в минимальных Docker-контейнерах), рассмотрите использование grep или других POSIX-совместимых методов.

Обработка ошибок

Для производственных скриптов добавьте обработку ошибок:

bash
#!/bin/bash

string="Моя строка"
substring="foo"

if [[ -z "$string" ]]; then
    echo "Ошибка: Строка пуста" >&2
    exit 1
fi

if [[ "$string" == *"$substring"* ]]; then
    echo "Подстрока '$substring' найдена в строке"
else
    echo "Подстрока '$substring' не найдена"
fi

Заключение

  1. В большинстве случаев используйте метод [[ $string == *"подстрока"* ]] - он читаемый, эффективный и встроен в Bash.

  2. Для критически важных к производительности приложений рассмотрите подход с оператором case, который показал себя более эффективным.

  3. Избегайте метода с grep, если вам не нужны специально сопоставление без учета регистра или возможности регулярных выражений.

  4. Всегда заключайте переменные в кавычки, чтобы предотвратить проблемы с разделением слов и подстановкой имен файлов.

  5. Помните, что не все среды имеют Bash - если вы пишете переносимые скрипты, протестируйте выбранный метод в целевой среде.

Правильный способ проверки наличия подстрок в Bash зависит от ваших конкретных потребностей, но оператор [[ с подстановочными знаками обеспечивает лучший баланс читаемости, производительности и совместимости для большинства случаев использования.