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

2576

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

string="My string"

Как я могу проверить, содержит ли она другую строку?

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

Где ??мой неизвестный оператор. Я использую эхо и grep?

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

Это выглядит немного неуклюже.

davidsheldon
источник
4
Привет, если пустые строки являются ложными, почему вы считаете это неуклюжим? Это был единственный способ, который работал для меня, несмотря на предложенные решения.
ericson.cepeda
1
Вы можете использовать exprкоманду здесь
cli__
4
Вот один из вариантов послеродовых оболочек: stackoverflow.com/questions/2829613/…
сэх

Ответы:

3659

Вы также можете использовать ответ Маркуса (* подстановочные знаки) вне оператора case, если вы используете двойные скобки:

string='My long string'
if [[ $string == *"My long"* ]]; then
  echo "It's there!"
fi

Обратите внимание, что пробелы в строке иглы должны быть помещены между двойными кавычками, а *подстановочные знаки должны быть снаружи. Также обратите внимание, что используется простой оператор сравнения (т.е. ==), а не оператор регулярного выражения =~.

Адам Беллер
источник
127
Также обратите внимание, что вы можете отменить сравнение, просто переключившись на! = В тесте. Спасибо за ответ!
Куинн Тейлор
63
@Jonik: Вы можете пропустить Шебанг или иметь его как #!/bin/sh. Попробуй #!/bin/bashвместо этого.
Приостановлено до дальнейшего уведомления.
10
Оставьте пробел между скобками и содержимым.
Пол Прайс
17
Вам не нужно заключать переменные в кавычки внутри [[]]. Это будет работать так же хорошо: [[$ string == $ needle ]] && echo found
Orwellophile
13
@ Orwellophile Осторожно! Вы можете опустить только двойные кавычки в первом аргументе [[. Смотрите ideone.com/ZSy1gZ
nyuszika7h
613

Если вы предпочитаете подход регулярных выражений:

string='My string';

if [[ $string =~ "My" ]]
then
   echo "It's there!"
fi
Мэтт Тардифф
источник
2
Пришлось заменить регулярное выражение egrep в сценарии bash, это работало отлично!
blast_hardcheese
114
=~Оператор уже ищет всю строку на матч; что .*«s здесь посторонний. Кроме того, кавычки, как правило, предпочтительнее обратной косой черты:[[ $string =~ "My s" ]]
букзор
16
@bukzor Котировки перестали работать здесь, начиная с Bash 3.2+ : tiswww.case.edu/php/chet/bash/FAQE14) . Вероятно, лучше присвоить переменную (используя кавычки), а затем сравнить. Как это:re="My s"; if [[ $string =~ $re ]]
Seanf
36
Тест , если он НЕ содержит строку: if [[ ! "abc" =~ "d" ]]верно.
KrisWebDev
1
Обратите внимание, что порядок проведения теста имеет значение. Вывод следующей строки кода будет впереди 2.number=2; if [[ "1, 2, 4, 5" = *${number}* ]]; then echo forward $number; fi; if [[ *${number}* = "1, 2, 4, 5" ]]; then echo backwards $number; fi;
Доу ван дер Лест
358

Я не уверен в использовании оператора if, но вы можете получить аналогичный эффект с помощью оператора case:

case "$string" in 
  *foo*)
    # Do stuff
    ;;
esac
Маркус Грип
источник
76
Это, пожалуй, лучшее решение, так как оно переносимо для послеродовых оболочек. (он же не башизм)
технозавр
25
@technosaurus Я нахожу довольно странным критиковать "bashism" в вопросе, который имеет только тег bash :)
PP
39
@PP Это не столько критика, сколько предпочтение более универсального решения, чем более ограниченного. Пожалуйста, учтите, что спустя годы люди (как и я) зайдут на поиски этого ответа и, возможно, будут рады найти тот, который будет полезен в более широкой области, чем первоначальный вопрос. Как говорят в мире Open Source: «выбор хорош!»
Карл Смотриц
2
@technosaurus, FWIW [[ $string == *foo* ]]также работает в некоторых POSIX-совместимых версиях sh (например, /usr/xpg4/bin/shв Solaris 10) и ksh (> = 88)
maxschlepzig
3
Зола Busybox не справляется со звездочками [[... переключатель корпуса работал!
Рэй Фосс
233

stringContain варианты (совместимые или независимые от регистра)

Поскольку эти ответы о переполнении стека говорят в основном о Bash , я опубликовал независимый случай функцию Bash в самом конце этого поста ...

Во всяком случае, есть мой

Совместимый ответ

Поскольку уже есть много ответов, использующих специфичные для Bash функции, есть способ работать с более слабыми оболочками, такими как BusyBox :

[ -z "${string##*$reqsubstr*}" ]

На практике это может дать:

string='echo "My string"'
for reqsubstr in 'o "M' 'alt' 'str';do
  if [ -z "${string##*$reqsubstr*}" ] ;then
      echo "String '$string' contain substring: '$reqsubstr'."
    else
      echo "String '$string' don't contain substring: '$reqsubstr'."
    fi
  done

Это было проверено в Bash, Dash , KornShell ( ksh) и ash (BusyBox), и результат всегда:

String 'echo "My string"' contain substring: 'o "M'.
String 'echo "My string"' don't contain substring: 'alt'.
String 'echo "My string"' contain substring: 'str'.

В одну функцию

По словам @EeroAaltonen, вот версия того же демо, протестированная под теми же оболочками:

myfunc() {
    reqsubstr="$1"
    shift
    string="$@"
    if [ -z "${string##*$reqsubstr*}" ] ;then
        echo "String '$string' contain substring: '$reqsubstr'.";
      else
        echo "String '$string' don't contain substring: '$reqsubstr'."
    fi
}

Затем:

$ myfunc 'o "M' 'echo "My String"'
String 'echo "My String"' contain substring 'o "M'.

$ myfunc 'alt' 'echo "My String"'
String 'echo "My String"' don't contain substring 'alt'.

Обратите внимание: вы должны экранировать или заключить в двойные кавычки и / или двойные кавычки:

$ myfunc 'o "M' echo "My String"
String 'echo My String' don't contain substring: 'o "M'.

$ myfunc 'o "M' echo \"My String\"
String 'echo "My String"' contain substring: 'o "M'.

Простая функция

Это было протестировано под BusyBox, Dash и, конечно же, Bash:

stringContain() { [ -z "${2##*$1*}" ]; }

То теперь:

$ if stringContain 'o "M3' 'echo "My String"';then echo yes;else echo no;fi
no
$ if stringContain 'o "M' 'echo "My String"';then echo yes;else echo no;fi
yes

... Или если отправленная строка может быть пустой, как указано @Sjlver, функция станет такой:

stringContain() { [ -z "${2##*$1*}" ] && [ -z "$1" -o -n "$2" ]; }

или как предложено в комментарии Адриана Гюнтера , избегая -oпереключателей:

stringContain() { [ -z "${2##*$1*}" ] && { [ -z "$1" ] || [ -n "$2" ];};}

Финальная (простая) функция:

И инвертировать тесты, чтобы сделать их потенциально быстрее:

stringContain() { [ -z "$1" ] || { [ -z "${2##*$1*}" ] && [ -n "$2" ];};}

С пустыми строками:

$ if stringContain '' ''; then echo yes; else echo no; fi
yes
$ if stringContain 'o "M' ''; then echo yes; else echo no; fi
no

Независимо от регистра (только Bash!)

Для тестирования строк без учета регистра просто конвертируйте каждую строку в нижний регистр:

stringContain() {
    local _lc=${2,,}
    [ -z "$1" ] || { [ -z "${_lc##*${1,,}*}" ] && [ -n "$2" ] ;} ;}

Проверьте:

stringContain 'o "M3' 'echo "my string"' && echo yes || echo no
no
stringContain 'o "My' 'echo "my string"' && echo yes || echo no
yes
if stringContain '' ''; then echo yes; else echo no; fi
yes
if stringContain 'o "M' ''; then echo yes; else echo no; fi
no
Ф. Хаури
источник
1
Это было бы еще лучше, если бы вы могли найти какой-то способ поместить это в функцию.
Ээро Аалтонен
2
@EeroAaltonen Как найти мою (новую добавленную) функцию?
Ф. Хаури
2
Я знаю! найти . имя "*" | xargs grep "myfunc" 2> / dev / null
eggmatters
6
Это замечательно, потому что это так совместимо. Одна ошибка, однако: она не работает, если строка сена пуста. Правильная версия будет string_contains() { [ -z "${2##*$1*}" ] && [ -n "$2" -o -z "$1" ]; } заключительной мыслью: содержит ли пустая строка пустую строку? Версия выше вещи да (из-за -o -z "$1"части).
Сильвер
3
+1. Отлично! Для меня я изменил порядок stringContain () {[-z "$ {1 ## * $ 2 *}"] && [-z "$ 2" -o -n "$ 1"]; }; «Поиск где» «Найти что». Работа в busybox. Принятый ответ выше не работает в busybox.
user3439968
150

Вы должны помнить, что сценарии оболочки - это не столько язык, сколько набор команд. Инстинктивно вы думаете, что этот «язык» требует, чтобы вы следовали ifс a [или a [[. Обе они являются просто командами, которые возвращают состояние выхода, указывающее на успех или неудачу (как и любая другая команда). По этой причине я бы использовал grep, а не [команду.

Просто делать:

if grep -q foo <<<"$string"; then
    echo "It's there"
fi

Теперь, когда вы рассматриваете ifтестирование состояния завершения команды, которая следует за ней (завершается точкой с запятой), почему бы не пересмотреть источник строки, которую вы тестируете?

## Instead of this
filetype="$(file -b "$1")"
if grep -q "tar archive" <<<"$filetype"; then
#...

## Simply do this
if file -b "$1" | grep -q "tar archive"; then
#...

-qОпция делает Grep не выводить ничего, как мы только хотим , код возврата. <<<заставляет оболочку развернуть следующее слово и использовать его в качестве входных данных для команды, однострочной версии <<документа здесь (я не уверен, является ли это стандартным или Bashism).

Марк Бейкер
источник
7
они называются здесь строками (3.6.7) Я верю, что это башизм
alex.pilon
10
можно также использовать процесс подстановки if grep -q foo <(echo somefoothing); then
larsr
Обратите внимание, что echoэто непереносимо, если вы передаете переменную, используйте printf '%s' "$stringвместо этого.
nyuszika7h
5
Стоимость этого очень grep -q foo <<<"$mystring"высока : выполнение 1 вилки, это башизм и echo $mystring | grep -q foo2 вилки (одна для трубы, а вторая для бега /path/to/grep)
Ф. Хаури
1
@BrunoBronosky echoбез флагов может по-прежнему иметь непредвиденные проблемы с переносимостью, если строка аргумента содержит последовательности с обратной косой чертой. echo "nope\c"ожидается, что на некоторых платформах будет работать как echo -e "nope"на некоторых других. printf '%s' "nope"противprintf '%s\n' 'nope\c'
tripleee
92

Принятый ответ лучше, но, поскольку есть несколько способов сделать это, вот другое решение:

if [ "$string" != "${string/foo/}" ]; then
    echo "It's there!"
fi

${var/search/replace}это $varс первым экземпляром searchзаменено replace, если он найден (это не меняет $var). Если вы попытаетесь заменить fooничем, а строка изменилась, то, очевидно, fooбыл найден.

ephemient
источник
5
Решение ephemient выше:> `if [" $ string "! =" $ {string / foo /} "]; затем эхо "Это там!" fi` полезен при использовании золы оболочки BusyBox . Принятое решение не работает с BusyBox, потому что некоторые регулярные выражения bash не реализованы.
TPoschel
1
неравенство разницы. Довольно странная мысль! Я люблю это
nitinr708
1
если только ваша строка не 'foo'
venimus
Я сам написал то же самое решение (потому что мой переводчик не брал лучшие ответы), затем отправился на поиски лучшего, но нашел это!
BuvinJ
56

Так что есть много полезных решений вопроса - но какой из них самый быстрый / использует наименьшее количество ресурсов?

Повторные тесты с использованием этого кадра:

/usr/bin/time bash -c 'a=two;b=onetwothree; x=100000; while [ $x -gt 0 ]; do TEST ; x=$(($x-1)); done'

Замена TEST каждый раз:

[[ $b =~ $a ]]           2.92 user 0.06 system 0:02.99 elapsed 99% CPU

[ "${b/$a//}" = "$b" ]   3.16 user 0.07 system 0:03.25 elapsed 99% CPU

[[ $b == *$a* ]]         1.85 user 0.04 system 0:01.90 elapsed 99% CPU

case $b in *$a):;;esac   1.80 user 0.02 system 0:01.83 elapsed 99% CPU

doContain $a $b          4.27 user 0.11 system 0:04.41 elapsed 99%CPU

(doContain был в ответе Ф. Хури)

И для хихиканья:

echo $b|grep -q $a       12.68 user 30.86 system 3:42.40 elapsed 19% CPU !ouch!

Таким образом, опция простого замещения предсказуемо выигрывает либо в расширенном тесте, либо в случае. Чехол переносной.

Выпадение до 100000 greps предсказуемо больно! Старое правило об использовании внешних утилит без необходимости сохраняется.

Пол Хеддерли
источник
4
Аккуратный ориентир. Убедил меня использовать [[ $b == *$a* ]].
Безумный физик
2
Если я правильно читаю, caseвыигрывает с наименьшим общим временем. Вы пропустили звездочку после того, $b in *$aкак. Я получаю немного более быстрые результаты, [[ $b == *$a* ]]чем за caseисправленную ошибку, но, конечно, это может зависеть и от других факторов.
tripleee
1
ideone.com/5roEVt исправил мой эксперимент с некоторыми дополнительными ошибками и тестами для другого сценария (где строка на самом деле отсутствует в более длинной строке). Результаты во многом схожи; [[ $b == *$a* ]]быстрый и caseпочти такой же быстрый (и приятно POSIX-совместимый).
tripleee
28

Это также работает:

if printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
  printf "Found needle in haystack"
fi

И отрицательный тест это:

if ! printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
  echo "Did not find needle in haystack"
fi

Я полагаю, что этот стиль немного более классический - меньше зависит от особенностей оболочки Bash.

--Аргумент чисто POSIX паранойя, используется для защищенных от входных строк , подобных опции, таких как --abcили -a.

Примечание. В узком цикле этот код будет работать намного медленнее, чем при использовании внутренних функций оболочки Bash, поскольку один (или два) отдельных процесса будут создаваться и соединяться через каналы.

kevinarpe
источник
5
... но ОП не говорит, какая версия bash; Например, старые версии Bash (такие, как часто у Solaris) могут не включать эти новые функции Bash. (Я столкнулся с этой точной проблемой (сопоставление шаблонов bash не реализовано) в Solaris w / bash 2.0)
Майкл
2
echoявляется непереносимым, вы должны использовать printf '%s' "$haystackвместо этого.
nyuszika7h
2
Нет, просто избегайте echoвсего, кроме буквального текста без escape-символов, которые не начинаются с a -. Это может работать для вас, но это не портативно. Даже bash echoбудет вести себя по-разному в зависимости от того, установлена ​​ли xpg_echoопция. PS: я забыл закрыть двойную кавычку в моем предыдущем комментарии.
nyuszika7h
1
@kevinarpe Я не уверен, --не указан в спецификации POSIX дляprintf , но вы должны использовать в printf '%s' "$anything"любом случае, чтобы избежать проблем, если $anythingсодержит %символ.
nyuszika7h
1
@kevinarpe Исходя из этого, это, вероятно, так.
nyuszika7h
21

Bash 4+ примеров. Примечание: неиспользование кавычек приведет к проблемам, когда слова содержат пробелы и т. Д. Всегда заключайте в Bash, IMO.

Вот несколько примеров Bash 4+:

Пример 1, проверьте «да» в строке (без учета регистра):

    if [[ "${str,,}" == *"yes"* ]] ;then

Пример 2, проверьте «да» в строке (без учета регистра):

    if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then

Пример 3, проверьте «да» в строке (с учетом регистра):

     if [[ "${str}" == *"yes"* ]] ;then

Пример 4, проверьте «да» в строке (с учетом регистра):

     if [[ "${str}" =~ "yes" ]] ;then

Пример 5, точное совпадение (с учетом регистра):

     if [[ "${str}" == "yes" ]] ;then

Пример 6, точное совпадение (без учета регистра):

     if [[ "${str,,}" == "yes" ]] ;then

Пример 7, точное совпадение:

     if [ "$a" = "$b" ] ;then

Пример 8, подстановочный знак .ext (без учета регистра):

     if echo "$a" | egrep -iq "\.(mp[3-4]|txt|css|jpg|png)" ; then

Наслаждаться.

Майк К
источник
17

Как насчет этого:

text="   <tag>bmnmn</tag>  "
if [[ "$text" =~ "<tag>" ]]; then
   echo "matched"
else
   echo "not matched"
fi
млрд.
источник
2
= ~ для соответствия регулярному выражению, следовательно, слишком мощное для целей ОП.
16

Как Павел упоминал в своем сравнении производительности:

if echo "abcdefg" | grep -q "bcdef"; then
    echo "String contains is true."
else
    echo "String contains is not true."
fi

Это соответствует POSIX, как 'case' $ string 'в' ответе, предоставленном Маркусом , но его немного легче прочитать, чем ответ оператора case. Также обратите внимание, что это будет намного медленнее, чем использование оператора case. Как указывал Пол, не используйте это в цикле.

Самуил
источник
11

Этот ответ переполнения стека был единственным, кто ловил пробел и тире символов:

# For null cmd arguments checking   
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found
Йордан Георгиев
источник
Это ответ на этот же вопрос.
Питер Мортенсен
9
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"
Jahid
источник
Я добавлю, что echo "Couldn't findоператор в конце является хорошим трюком для возврата 0 состояний выхода для этих соответствующих команд.
Никоджименез
@nicodjimenez вы не можете больше ориентироваться на статус выхода с этим решением. Статус выхода поглощается сообщениями о состоянии ...
Джахид
1
Это именно то, что я имел в виду ... Если у вас его нет, || echo "Couldn't find"вы вернете состояние выхода из ошибки, если не будет совпадения, чего вы, возможно, не захотите, если вы запускаете конвейер CI, например, где вы хотите, чтобы все команды возвращались статусы выхода без ошибок
nicodjimenez
9

Один:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'
chemila
источник
2
exprэто одна из тех утилит для швейцарских армейских ножей, которые обычно могут делать все, что вам нужно, как только вы поймете, как это сделать, но после внедрения вы никогда не сможете вспомнить, почему или как он делает то, что делает, так что вы никогда не трогай его снова и надейся, что он никогда не перестанет делать то, что делает.
Майкл
@AloisMahdal Я никогда не голосовал против, я просто постулирую, почему были поданы голоса. Предупредительный комментарий. Я использую expr, в редких случаях, когда переносимость не позволяет использовать bash (например, несовместимое поведение в более старых версиях), tr (несовместимый везде) или sed (иногда слишком медленный). Но из личного опыта, когда бы я ни перечитывал эти expr-измы, я должен вернуться на страницу руководства. Итак, я бы просто прокомментировал, что каждое использование exprбудет прокомментировано ...
Майкл
1
Было время, когда у тебя была только оригинальная оболочка Борна. В нем отсутствовали некоторые обычно необходимые функции, поэтому инструменты, такие как exprи testбыли реализованы для их выполнения. В наше время обычно существуют лучшие инструменты, многие из которых встроены в любую современную оболочку. Я думаю, testчто все еще там висит, но, кажется, никто не пропал expr.
tripleee
6

Мне нравится Сед.

substr="foo"
nonsub="$(echo "$string" | sed "s/$substr//")"
hassub=0 ; [ "$string" != "$nonsub" ] && hassub=1

Редактировать, Логика:

  • Используйте sed, чтобы удалить экземпляр подстроки из строки

  • Если новая строка отличается от старой, существует подстрока

ездить
источник
2
Пожалуйста, добавьте некоторые объяснения. Передача базовой логики важнее, чем просто предоставление кода, потому что это помогает ОП и другим читателям самим решить эту и подобные проблемы
Зулан,
5

grep -q полезно для этого.

То же самое с использованием awk:

string="unix-bash 2389"
character="@"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'

Вывод:

не обнаружена

string="unix-bash 2389"
character="-"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'

Вывод:

Нашел

Первоисточник: http://unstableme.blogspot.com/2008/06/bash-search-letter-in-string-awk.html

nyuszika7h
источник
3
echoявляется непереносимым, вы должны использовать printf '%s' "$string"вместо этого. Я редактирую ответ, потому что пользователь, кажется, больше не существует.
nyuszika7h
echoКаким образом не является портативным, @ nyuszika7h?
starbeamrainbowlabs
5

Я обнаружил, что эта функциональность нужна довольно часто, поэтому я использую самодельную функцию оболочки в своем .bashrcподобии, которая позволяет мне использовать ее так часто, как мне нужно, с легко запоминающимся именем:

function stringinstring()
{
    case "$2" in
       *"$1"*)
          return 0
       ;;
    esac
    return 1
}

Чтобы проверить $string1, содержится ли (скажем, abc ) в $string2(скажем, 123abcABC ), мне просто нужно запустить stringinstring "$string1" "$string2"и проверить, например, возвращаемое значение

stringinstring "$str1" "$str2"  &&  echo YES  ||  echo NO
Курт Пфайфл
источник
[["$ str" == $ substr ]] && echo YES || Эхо НЕТ
Элиазе
Я почти уверен, что xвзлом требуется только для очень старых оболочек.
nyuszika7h
5

Мой .bash_profile файл и как я использовал grep:

Если переменная окружения PATH включает мои две binдиректории, не добавляйте их,

# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

U=~/.local.bin:~/bin

if ! echo "$PATH" | grep -q "home"; then
    export PATH=$PATH:${U}
fi
Лесли Сатенштейн
источник
1
Это ответ?
codeforester
upvote. зачем изучать, как Bash делает это, когда grep, гораздо более мощный, более чем вероятно будет доступен. также расширить его немного дальше за счет сопоставления со списком шаблонов: grep -q -E 'pattern1|...|patternN'.
Мохамед Бана,
4

Расширение вопроса, на который здесь дан ответ Как узнать, содержит ли строка другую строку в POSIX sh? :

Это решение работает со специальными символами:

# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
    string="$1"
    substring="$2"

    if echo "$string" | $(type -p ggrep grep | head -1) -F -- "$substring" >/dev/null; then
        return 0    # $substring is in $string
    else
        return 1    # $substring is not in $string
    fi
}

contains "abcd" "e" || echo "abcd does not contain e"
contains "abcd" "ab" && echo "abcd contains ab"
contains "abcd" "bc" && echo "abcd contains bc"
contains "abcd" "cd" && echo "abcd contains cd"
contains "abcd" "abcd" && echo "abcd contains abcd"
contains "" "" && echo "empty string contains empty string"
contains "a" "" && echo "a contains empty string"
contains "" "a" || echo "empty string does not contain a"
contains "abcd efgh" "cd ef" && echo "abcd efgh contains cd ef"
contains "abcd efgh" " " && echo "abcd efgh contains a space"

contains "abcd [efg] hij" "[efg]" && echo "abcd [efg] hij contains [efg]"
contains "abcd [efg] hij" "[effg]" || echo "abcd [efg] hij does not contain [effg]"

contains "abcd *efg* hij" "*efg*" && echo "abcd *efg* hij contains *efg*"
contains "abcd *efg* hij" "d *efg* h" && echo "abcd *efg* hij contains d *efg* h"
contains "abcd *efg* hij" "*effg*" || echo "abcd *efg* hij does not contain *effg*"
Алекс Скрипник
источник
Тест contains "-n" "n"здесь не работает, потому echo -nчто проглотит -nкак опцию! printf "%s\n" "$string"Вместо этого популярным решением является использование .
Joeytwiddle
отлично, решенная строка содержит пробелы
dengApro
4

Поскольку вопрос POSIX / BusyBox закрыт без предоставления правильного ответа (IMHO), я выложу ответ здесь.

Кратчайший возможный ответ:

[ ${_string_##*$_substring_*} ] || echo Substring found!

или

[ "${_string_##*$_substring_*}" ] || echo 'Substring found!'

Обратите внимание , что двойной хэш является обязательным с некоторыми оболочками ( ash). Выше будет оцениваться, [ stringvalue ]когда подстрока не найдена. Это не возвращает ошибку. Когда подстрока найдена, результат является пустым, и он оценивает [ ]. Это выдаст код ошибки 1, так как строка полностью заменена (из-за* ).

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

[ -z "${_string_##*$_substring_*}" ] && echo 'Substring found!'

или

[ -n "${_string_##*$_substring_*}" ] || echo 'Substring found!'

Другой:

[ "${_string_##$_substring_}" != "$_string_" ] && echo 'Substring found!'

или

[ "${_string_##$_substring_}" = "$_string_" ] || echo 'Substring found!'

Обратите внимание на один знак равенства!

FifthAxiom
источник
3

Точное совпадение слов:

string='My long string'
exactSearch='long'

if grep -E -q "\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
  then
    echo "It's there"
  fi
Эдуардо Куомо
источник
3

Попробуйте ообаш.

Это библиотека строк в стиле OO для Bash 4. Она поддерживает немецкие умлауты. Это написано на Bash.

Многие функции: -base64Decode, -base64Encode, -capitalize, -center, -charAt, -concat, -contains, -count, -endsWith, -equals, -equalsIgnoreCase, -reverse, -hashCode, -indexOf, -isAlnum, -isAlpha, -isAscii, -isDigit, -isEmpty, -isHexDigit, -isLowerCase, -isSpace, -isPrintable, -isUpperCase, -isVisible, -lastIndexOf, -length, -matches, -replaceAll, -replaceFirst, -startsWith, -substring, -swapCase, -toLowerCase, -toString, -toUpperCase, -trim, и -zfill.

Посмотрите на содержащийся пример:

[Desktop]$ String a testXccc
[Desktop]$ a.contains tX
true
[Desktop]$ a.contains XtX
false

oobash доступен на Sourceforge.net .

андреас
источник
2

Я использую эту функцию (одна зависимость не включена, но очевидна). Он проходит испытания, показанные ниже. Если функция возвращает значение> 0, то строка была найдена. Вы можете так же легко вернуть 1 или 0 вместо этого.

function str_instr {
   # Return position of ```str``` within ```string```.
   # >>> str_instr "str" "string"
   # str: String to search for.
   # string: String to search.
   typeset str string x
   # Behavior here is not the same in bash vs ksh unless we escape special characters.
   str="$(str_escape_special_characters "${1}")"
   string="${2}"
   x="${string%%$str*}"
   if [[ "${x}" != "${string}" ]]; then
      echo "${#x} + 1" | bc -l
   else
      echo 0
   fi
}

function test_str_instr {
   str_instr "(" "'foo@host (dev,web)'" | assert_eq 11
   str_instr ")" "'foo@host (dev,web)'" | assert_eq 19
   str_instr "[" "'foo@host [dev,web]'" | assert_eq 11
   str_instr "]" "'foo@host [dev,web]'" | assert_eq 19
   str_instr "a" "abc" | assert_eq 1
   str_instr "z" "abc" | assert_eq 0
   str_instr "Eggs" "Green Eggs And Ham" | assert_eq 7
   str_instr "a" "" | assert_eq 0
   str_instr "" "" | assert_eq 0
   str_instr " " "Green Eggs" | assert_eq 6
   str_instr " " " Green "  | assert_eq 1
}
Итан Пост
источник
Ожидание! Что это зависимость?
Питер Мортенсен
Функция "str_escape_special_characters". Он находится в файле GitHub arcshell_str.sh. arcshell.io доставит вас туда.
Итан Пост
0
msg="message"

function check {
    echo $msg | egrep [abc] 1> /dev/null

    if [ $? -ne 1 ];
    then 
        echo "found" 
    else 
        echo "not found" 
    fi
}

check

Это найдет любое вхождение a или b или c

BobMonk
источник
0

Общий пример стога сена иглы следующий с переменными

#!/bin/bash

needle="a_needle"
haystack="a_needle another_needle a_third_needle"
if [[ $haystack == *"$needle"* ]]; then
    echo "needle found"
else
    echo "needle NOT found"
fi
Pipo
источник