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

У меня есть строка в 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

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

23.10.2008 12:37:31
Привет, если пустые строки ложные, почему вы считаете это неуклюжим? Это был единственный способ, который работал для меня, несмотря на предложенные решения.
ericson.cepeda 5.05.2015 06:14:54
Вы можете использовать exprкоманду здесь
cli__ 2.03.2016 03:08:14
Вот один для Posix оболочек: stackoverflow.com/questions/2829613/...
sehe 8.04.2016 15:31:21
26 ОТВЕТОВ
РЕШЕНИЕ

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

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

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

3573
17.04.2020 01:20:42
Также обратите внимание, что вы можете отменить сравнение, просто переключившись на! = В тесте. Спасибо за ответ!
Quinn Taylor 30.07.2009 17:14:51
@Jonik: Вы можете пропустить Шебанг или иметь его как #!/bin/sh. Попробуй #!/bin/bashвместо этого.
Paused until further notice. 17.12.2010 05:18:19
Оставьте пробел между скобками и содержимым.
Paul Price 22.01.2013 16:43:56
Вам не нужно заключать переменные в кавычки внутри [[]]. Это будет работать так же хорошо: [[$ string == $ needle ]] && echo found
Orwellophile 9.08.2013 05:07:17
@ Orwellophile Осторожно! Вы можете опустить только двойные кавычки в первом аргументе для [[. Смотрите ideone.com/ZSy1gZ
nyuszika7h 11.06.2014 17:53:09

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

case "$string" in 
  *foo*)
    # Do stuff
    ;;
esac
349
23.10.2008 12:47:04
Это, вероятно, лучшее решение, так как оно переносимо для послеродовых оболочек. (он же не башизм)
technosaurus 4.01.2014 17:02:32
@technosaurus Я нахожу довольно странным критиковать «bashism» в вопросе, который имеет только тег bash :)
P.P 17.12.2015 23:27:44
@PP Это не столько критика, сколько предпочтение более универсального решения, чем более ограниченного. Пожалуйста, учтите, что спустя годы люди (как и я) зайдут на поиски этого ответа и, возможно, будут рады найти тот, который будет полезен в более широкой области, чем первоначальный вопрос. Как говорят в мире Open Source: «выбор хорош!»
Carl Smotricz 3.06.2016 07:56:28
@technosaurus, FWIW [[ $string == *foo* ]]также работает в некоторых POSIX-совместимых версиях sh (например, /usr/xpg4/bin/shв Solaris 10) и ksh (> = 88)
maxschlepzig 1.05.2017 10:00:33
Зола Busybox не справляется со звездочками [[... переключатель корпуса работал!
Ray Foss 25.03.2019 14:50:53

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

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

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

92
12.06.2013 05:33:48
Решение ephemient выше:> `if [" $ string "! =" $ {string / foo /} "]; затем эхо "Это там!" fi` полезен при использовании золы оболочки BusyBox . Принятое решение не работает с BusyBox, потому что некоторые регулярные выражения bash не реализованы.
TPoschel 8.10.2010 12:41:48
неравенство различий. Довольно странная мысль! Я люблю это
nitinr708 1.08.2017 08:58:26
если только ваша строка не 'foo'
venimus 12.07.2019 17:31:56
Я сам написал то же самое решение (потому что мой переводчик не брал лучшие ответы), затем отправился на поиски лучшего, но нашел это!
BuvinJ 15.10.2019 20:25:00

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

string='My string';

if [[ $string =~ "My" ]]
then
   echo "It's there!"
fi
600
20.05.2019 17:41:35
Пришлось заменить регулярное выражение egrep в сценарии bash, это работало отлично!
blast_hardcheese 14.02.2012 05:10:19
=~Оператор уже ищет всю строку на матч; что .*«s здесь посторонний. Кроме того, кавычки, как правило, предпочтительнее обратной косой черты:[[ $string =~ "My s" ]]
bukzor 5.06.2013 18:15:56
@bukzor Котировки перестали работать здесь, начиная с Bash 3.2+ : tiswww.case.edu/php/chet/bash/FAQE14) . Вероятно, лучше присвоить переменную (используя кавычки), а затем сравнить. Как это:re="My s"; if [[ $string =~ $re ]]
seanf 12.05.2015 00:55:47
Тест , если он НЕ содержит строку: if [[ ! "abc" =~ "d" ]]верно.
KrisWebDev 24.01.2016 14:57:20
Обратите внимание, что порядок проведения теста имеет значение. Вывод следующей строки кода будет впереди 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;
Douwe van der Leest 1.08.2018 11:40:09

Вы должны помнить, что сценарии оболочки - это не столько язык, сколько набор команд. Инстинктивно вы думаете, что этот «язык» требует, чтобы вы следовали 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).

147
1.01.2020 13:33:50
они называются здесь строками (3.6.7) Я верю, что это башизм
alex.pilon 20.10.2011 17:03:14
можно также использовать процесс подстановки if grep -q foo <(echo somefoothing); then
larsr 19.12.2011 12:45:23
Обратите внимание, что echoэто непереносимо, если вы передаете переменную, используйте printf '%s' "$stringвместо этого.
nyuszika7h 11.06.2014 18:05:53
Стоимость этого очень grep -q foo <<<"$mystring"высока : выполнение 1 вилки, это башизм и echo $mystring | grep -q foo2 вилки (одна для трубы, а вторая для бега /path/to/grep)
F. Hauri 20.04.2015 08:40:48
@BrunoBronosky echoбез флагов может по-прежнему иметь непредвиденные проблемы с переносимостью, если строка аргумента содержит последовательности с обратной косой чертой. echo "nope\c"ожидается, что на некоторых платформах будет работать как echo -e "nope"на некоторых других. printf '%s' "nope"противprintf '%s\n' 'nope\c'
tripleee 12.04.2018 06:45:29

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

5
28.03.2015 16:54:12
echoявляется непереносимым, вы должны использовать printf '%s' "$string"вместо этого. Я редактирую ответ, потому что пользователь, кажется, больше не существует.
nyuszika7h 11.06.2014 18:14:36

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

text="   <tag>bmnmn</tag>  "
if [[ "$text" =~ "<tag>" ]]; then
   echo "matched"
else
   echo "not matched"
fi
17
15.12.2014 16:37:57
= ~ для соответствия регулярному выражению, следовательно, слишком мощный для цели OP.
user49586 9.02.2009 06:37:25

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

Это библиотека строк в стиле 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 .

3
1.01.2020 13:34:54

Один:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'
9
13.02.2016 17:31:54
exprэто одна из тех утилит для швейцарских армейских ножей, которые обычно могут делать все, что вам нужно, как только вы поймете, как это сделать, но после внедрения вы никогда не сможете вспомнить, почему или как он делает то, что делает, так что вы никогда не трогай его снова и надейся, что он никогда не перестанет делать то, что делает.
michael 10.08.2013 05:50:44
@AloisMahdal Я никогда не голосовал против, я просто постулирую, почему были поданы голоса. Предупредительный комментарий. Я использую expr, в редких случаях, когда переносимость не позволяет использовать bash (например, несовместимое поведение в более старых версиях), tr (несовместимый везде) или sed (иногда слишком медленный). Но из личного опыта, когда бы я ни перечитывал эти expr-измы, я должен вернуться на страницу руководства. Итак, я бы просто прокомментировал, что каждое использование exprбудет прокомментировано ...
michael 4.03.2014 19:13:26
Было время, когда у тебя была только оригинальная оболочка Борна. В нем отсутствовали некоторые обычно необходимые функции, поэтому инструменты, такие как exprи testбыли реализованы для их выполнения. В наше время обычно существуют лучшие инструменты, многие из которых встроены в любую современную оболочку. Я думаю test, все еще там висит, но, кажется, никто не пропал expr.
tripleee 10.02.2016 18:12:41

Я обнаружил, что эта функциональность нужна довольно часто, поэтому я использую самодельную функцию оболочки в своем .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
5
1.01.2020 13:41:43
[["$ str" == $ substr ]] && echo YES || Эхо НЕТ
elyase 11.12.2012 21:34:39
Я почти уверен, что xвзлом требуется только для очень старых оболочек.
nyuszika7h 11.06.2014 18:08:55

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

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, поскольку один (или два) отдельных процесса будут создаваться и соединяться через каналы.

28
11.06.2015 23:53:20
... но ОП не говорит, какая версия bash; Например, старые версии Bash (такие, как часто у Solaris) могут не включать эти новые функции Bash. (Я столкнулся с этой точной проблемой (сопоставление шаблонов bash не реализовано) в Solaris с bash 2.0)
michael 10.08.2013 05:43:32
echoявляется непереносимым, вы должны использовать printf '%s' "$haystackвместо этого.
nyuszika7h 11.06.2014 18:03:49
Нет, просто избегайте echoвсего, кроме буквального текста без escape-символов, которые не начинаются с a -. Это может работать для вас, но это не портативно. Даже bash echoбудет вести себя по-разному в зависимости от того, установлена ​​ли xpg_echoопция. PS: я забыл закрыть двойную кавычку в моем предыдущем комментарии.
nyuszika7h 16.08.2014 11:18:03
@kevinarpe Я не уверен, --не указан в спецификации POSIX дляprintf , но вы должны использовать в printf '%s' "$anything"любом случае, чтобы избежать проблем, если $anythingсодержит %символ.
nyuszika7h 17.03.2015 13:45:38
@kevinarpe Исходя из этого, это, вероятно, так.
nyuszika7h 17.06.2016 10:49:39

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

# For null cmd arguments checking   
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found
11
1.01.2020 13:43:55
Это ответ на этот же вопрос.
Peter Mortensen 1.01.2020 13:43:32

Поскольку эти ответы о переполнении стека в основном рассказывают о 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
229
1.01.2020 13:56:56
Это было бы еще лучше, если бы вы могли найти какой-то способ поместить это в функцию.
Eero Aaltonen 10.12.2013 08:35:24
@EeroAaltonen Как найти мою (новую добавленную) функцию?
F. Hauri 6.05.2014 18:23:46
Я знаю! найти . имя "*" | xargs grep "myfunc" 2> / dev / null
eggmatters 15.07.2014 20:20:36
Это замечательно, потому что это так совместимо. Одна ошибка, однако: она не работает, если строка сена пуста. Правильная версия будет string_contains() { [ -z "${2##*$1*}" ] && [ -n "$2" -o -z "$1" ]; } заключительной мыслью: содержит ли пустая строка пустую строку? Версия выше вещи да (из-за -o -z "$1"части).
Sjlver 24.10.2014 12:14:28
+1. Очень хорошо! Для меня я изменил порядок stringContain () {[-z "$ {1 ## * $ 2 *}"] && [-z "$ 2" -o -n "$ 1"]; }; «Поиск где» «Найти что». Работа в busybox. Принятый ответ выше не работает в busybox.
user3439968 14.11.2014 19:11:04

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

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

/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 предсказуемо больно! Старое правило об использовании внешних утилит без необходимости сохраняется.

55
1.01.2020 14:13:38
Аккуратный ориентир. Убедил меня использовать [[ $b == *$a* ]].
Mad Physicist 13.07.2016 16:28:20
Если я правильно читаю, caseвыигрывает с наименьшим общим временем. Вы пропустили звездочку после того, $b in *$aкак. Я получаю немного более быстрые результаты, [[ $b == *$a* ]]чем за caseисправленную ошибку, но, конечно, это может зависеть и от других факторов.
tripleee 12.04.2018 06:59:08
ideone.com/5roEVt исправил мой эксперимент с некоторыми дополнительными ошибками и тестами для другого сценария (где строка на самом деле отсутствует в более длинной строке). Результаты во многом схожи; [[ $b == *$a* ]]быстрый и caseпочти такой же быстрый (и приятно POSIX-совместимый).
tripleee 12.04.2018 08:41:58

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

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. Как указывал Пол, не используйте это в цикле.

16
1.01.2020 14:15:42
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"
9
28.04.2015 19:55:58
Я добавлю, что echo "Couldn't findоператор в конце является хорошим трюком для возврата 0 состояний выхода для этих соответствующих команд.
nicodjimenez 16.10.2017 21:11:17
@nicodjimenez вы не можете больше ориентироваться на статус выхода с этим решением. Статус выхода поглощается сообщениями о статусе ...
Jahid 17.10.2017 05:56:16
Это именно то, что я имел в виду ... Если у вас его нет, || echo "Couldn't find"вы вернете состояние выхода из ошибки, если совпадения не будет, что может не понадобиться, если вы запускаете конвейер CI, например, где вы хотите, чтобы все команды возвращались статусы выхода без ошибок
nicodjimenez 17.10.2017 10:02:32

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

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

Изменить, Логика:

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

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

6
5.03.2016 14:42:02
Пожалуйста, добавьте некоторые объяснения. Передача базовой логики важнее, чем просто предоставление кода, потому что это помогает ОП и другим читателям самим решить эту и подобные проблемы
Zulan 5.03.2016 14:04:26

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

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
10.11.2016 14:56:18

Мой файл .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
5
1.01.2020 14:20:31
Это ответ?
codeforester 14.01.2017 06:01:17
upvote. зачем пытаться узнать, как это делает Bash, когда grep, гораздо более мощный, более чем вероятно будет доступен. также расширить его немного дальше за счет сопоставления со списком шаблонов: grep -q -E 'pattern1|...|patternN'.
Mohamed Bana 7.02.2017 13:37:55

Я использую эту функцию (одна зависимость не включена, но очевидна). Он проходит испытания, показанные ниже. Если функция возвращает значение> 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
}
2
11.04.2018 02:09:50
Ожидание! Что это зависимость?
Peter Mortensen 1.01.2020 14:22:10
Функция "str_escape_special_characters". Он находится в файле GitHub arcshell_str.sh. arcshell.io доставит вас туда.
Ethan Post 2.01.2020 05:47:49

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

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

20
1.01.2020 14:23:21

Расширение вопроса, на который здесь дан ответ Как узнать, содержит ли строка другую строку в 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*"
4
1.01.2020 14:27:27
Тест contains "-n" "n"здесь не работает, потому echo -nчто проглотит -nкак опцию! printf "%s\n" "$string"Вместо этого популярным решением является использование .
joeytwiddle 12.12.2019 10:34:38
отлично, решаемая строка содержит пробелы
dengApro 23.01.2020 12:25:31

Поскольку вопрос 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!'

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

4
1.01.2020 14:28:37
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

0
13.02.2020 00:22:58

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

#!/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
0
17.03.2020 10:34:37
case $string in (*foo*)
  # Do stuff
esac

Это тот же ответ, что и https://stackoverflow.com/a/229585/11267590 . Но простой стиль, а также POSIX-совместимый.

1
27.03.2020 10:42:14