Как проверить, содержит ли строка подстроку в 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
Это выглядит немного громоздко. как я могу сделать это более элегантным способом?
5 ответ(ов)
Если вы предпочитаете подход с использованием регулярных выражений, вы можете сделать это следующим образом:
string='My string'
if [[ $string =~ "My" ]]; then
echo "Присутствует!"
fi
Обратите внимание, что в данной конструкции используется проверка на соответствие строки с регулярным выражением внутри двойных квадратных скобок [[ ]]
. Если подстрока "My" найдена, то выполняется команда echo
с сообщением "Присутствует!".
Вы не уверены в использовании оператора if, но вы можете добиться аналогичного эффекта с помощью оператора case:
case "$string" in
*foo*)
# Выполнить нужные действия
;;
esac
Этот подход проверяет, содержит ли строка "$string"
подстроку foo
, и выполняет соответствующий блок кода, если условие истинно.
Следует помнить, что оболочка скриптов является скорее набором команд, чем полноценным языком. Вы инстинктивно думаете, что после if
вам нужно использовать [
или [[
. Но на самом деле это просто команды, которые возвращают статус выхода, указывающий на успех или неудачу (как и любая другая команда). Исходя из этого, я бы использовал grep
, а не команду [
.
Просто сделайте так:
if grep -q foo <<<"$string"; then
echo "Это там"
fi
Теперь, когда вы начинаете воспринимать if
как проверку статуса выхода следующей команды (с обязательно присутствующей точкой с запятой), стоит пересмотреть источник строки, которую вы проверяете.
## Вместо этого
filetype="$(file -b "$1")"
if grep -q "tar archive" <<<"$filetype"; then
#...
## Просто сделайте это
if file -b "$1" | grep -q "tar archive"; then
#...
Опция -q
заставляет grep
ничего не выводить, так как нам нужен только код возврата. Оператор <<<
заставляет оболочку интерпретировать следующее слово и использовать его как ввод для команды, это однострочная версия here-документа <<
(я не уверен, является ли это стандартом или особенностью Bash).
Принятый ответ хорош, но поскольку существует несколько способов решения этой задачи, вот еще один вариант:
if [ "$string" != "${string/foo/}" ]; then
echo "Слово найдено!"
fi
${var/search/replace}
— это $var
, в котором первое вхождение search
заменяется на replace
, если оно найдено (при этом сам $var
не изменяется). Если вы попытаетесь заменить foo
на пустую строку и строка при этом изменится, значит, foo
действительно было найдено.
Вопрос очень актуален, так как производительность и использование ресурсов — важные аспекты при выборе метода решения. Давайте посмотрим на результаты тестов, которые вы привели, и сравним их.
Используя следующую команду для тестирования:
/usr/bin/time bash -c 'a=two;b=onetwothree; x=100000; while [ $x -gt 0 ]; do TEST ; x=$(($x-1)); done'
Если подставить разные методы проверки наличия подстроки, то получается следующее:
[[ $b =~ $a ]]
— 2.92 user, 0.06 system, 0:02.99 elapsed[ "${b/$a//}" = "$b" ]
— 3.16 user, 0.07 system, 0:03.25 elapsed[[ $b == *$a* ]]
— 1.85 user, 0.04 system, 0:01.90 elapsedcase $b in *$a):;;esac
— 1.80 user, 0.02 system, 0:01.83 elapseddoContain $a $b
— 4.27 user, 0.11 system, 0:04.41 elapsed
И немного забавы:
echo $b|grep -q $a
— 12.68 user, 30.86 system, 3:42.40 elapsed (что, безусловно, довольно болезненно!)
Как видно из результатов, использование простого замещения (шаблон замены) занимает меньше всего времени. Также, вариант с case
имеет свои преимущества в портативности. В то время как использование внешнего утилита grep
значительно замедляет выполнение, что подтверждает правило — избегайте использования внешних утилит без необходимости.
В итоге, если вы хотите добиться максимальной производительности при проверке наличия подстроки, стоит рассмотреть использование синтаксиса [[ $b == *$a* ]]
или case
, так как они показывают наилучшие результаты.
Извлечение подстроки в Bash
Как выводить команды оболочки по мере их выполнения
Как запросить ввод Yes/No/Cancel в скрипте оболочки Linux?
Как объявить и использовать логические переменные в shell-скрипте?
Разница между sh и Bash