Как проверить, содержит ли строка подстроку в Bash
У меня есть строка в Bash:
string="My string"
Как проверить, содержит ли она другую строку? Я пробовал использовать:
if [ $string ?? 'foo' ]; then
echo "It's there!"
fi
Где ?? - это мой неизвестный оператор. Правильно ли использовать echo и grep?
if echo "$string" | grep 'foo'; then
echo "It's there!"
fi
Это кажется немного громоздким. Какой правильный способ проверять наличие подстрок в 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 предоставляет эффективную альтернативу:
string="Моя строка"
substring="foo"
case $string in
*"$substring"*)
echo "Подстрока найдена!"
;;
*)
echo "Подстрока не найдена"
;;
esac
Как отмечается в обсуждении на Stack Overflow, метод с case на самом деле эффективнее оператора [[ для поиска подстрок.
Использование регулярных выражений
Bash поддерживает сопоставление с регулярными выражениями с помощью оператора =~:
string="Моя строка"
substring="foo"
if [[ $string =~ .*"$substring".* ]]; then
echo "Подстрока найдена!"
fi
Использование внешних команд
Метод с grep
Хотя ваш подход с grep работает, его можно оптимизировать:
string="Моя строка"
substring="foo"
if echo "$string" | grep -q "$substring"; then
echo "Подстрока найдена!"
fi
Опция -q делает grep тихим и возвращает только код завершения. Однако, как отмечено на Linuxize, этот метод менее эффективен, так как требует создания нового процесса.
Альтернатива с here-document
Вместо echo можно использовать here-document:
if grep -q "$substring" <<< "$string"; then
echo "Подстрока найдена!"
fi
Расширенное сопоставление шаблонов
Несколько подстрок
Можно проверить наличие нескольких подстрок с помощью логических операторов:
string="Привет мир"
if [[ $string == *"Привет"* && $string == *"мир"* ]]; then
echo "Обе подстроки найдены!"
fi
Варианты шаблонов
Различные шаблоны с подстановочными знаками для разных нужд:
# Начинается с подстроки
if [[ $string == "foo"* ]]; then
echo "Строка начинается с 'foo'"
fi
# Заканчивается подстрокой
if [[ $string == *"foo" ]]; then
echo "Строка заканчивается на 'foo'"
fi
# Точное положение (не напрямую, но с помощью regex)
if [[ $string =~ foo ]]; then
echo "Содержит 'foo'"
fi
Сопоставление без учета регистра
Использование grep с флагом игнорирования регистра
string="Привет Мир"
substring="привет"
if echo "$string" | grep -qi "$substring"; then
echo "Подстрока найдена (без учета регистра)!"
fi
Использование shopt для сопоставления без учета регистра в Bash
shopt -s nocasematch
string="Привет Мир"
substring="привет"
if [[ $string == *"привет"* ]]; then
echo "Подстрока найдена (без учета регистра)!"
fi
shopt -u nocasematch # Выключить сопоставление без учета регистра
Сравнение производительности
На основе результатов исследований, вот как методы сравниваются по производительности:
- Оператор
case- наиболее эффективный, особенно для больших строк - Оператор
[[с подстановочными знаками - хорошая производительность, очень читаемый - Регулярные выражения (
=~) - более мощные, но медленнее, чем сопоставление шаблонов - Метод с
grep- наименее эффективный из-за накладных расходов на создание процесса
Как упоминается в ответе на Stack Overflow, обновление 2023 года подтвердило, что метод с case значительно эффективнее подходов с расширением параметров.
Лучшие практики
Всегда заключайте переменные в кавычки
# Хорошо
if [[ "$string" == *"foo"* ]]; then
# Плохо (может вызвать проблемы с пробелами или специальными символами)
if [[ $string == *foo* ]]; then
Обработка пустых строк
if [[ -n "$string" && "$string" == *"foo"* ]]; then
echo "Непустая строка содержит 'foo'"
fi
Используйте [[ вместо [
Оператор [[ более мощный и безопаснее, чем старая команда теста [:
# Лучше
if [[ $string == *"foo"* ]]; then
# Старый стиль, более ограниченный
if [ "$string" = *foo* ]; then # Это не будет работать с подстановочными знаками!
Учитывайте переносимость
Если вашему скрипту нужно работать в средах без Bash (например, в минимальных Docker-контейнерах), рассмотрите использование grep или других POSIX-совместимых методов.
Обработка ошибок
Для производственных скриптов добавьте обработку ошибок:
#!/bin/bash
string="Моя строка"
substring="foo"
if [[ -z "$string" ]]; then
echo "Ошибка: Строка пуста" >&2
exit 1
fi
if [[ "$string" == *"$substring"* ]]; then
echo "Подстрока '$substring' найдена в строке"
else
echo "Подстрока '$substring' не найдена"
fi
Заключение
-
В большинстве случаев используйте метод
[[ $string == *"подстрока"* ]]- он читаемый, эффективный и встроен в Bash. -
Для критически важных к производительности приложений рассмотрите подход с оператором
case, который показал себя более эффективным. -
Избегайте метода с
grep, если вам не нужны специально сопоставление без учета регистра или возможности регулярных выражений. -
Всегда заключайте переменные в кавычки, чтобы предотвратить проблемы с разделением слов и подстановкой имен файлов.
-
Помните, что не все среды имеют Bash - если вы пишете переносимые скрипты, протестируйте выбранный метод в целевой среде.
Правильный способ проверки наличия подстрок в Bash зависит от ваших конкретных потребностей, но оператор [[ с подстановочными знаками обеспечивает лучший баланс читаемости, производительности и совместимости для большинства случаев использования.