Як перевірити, чи містить рядок підрядку в Bash


2565

У мене є рядок у 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

Це виглядає трохи незграбно.


4
Привіт, якщо порожні рядки помилкові, чому ви вважаєте це незграбним? Це був єдиний спосіб, який працював для мене, незважаючи на запропоновані рішення.
ericson.cepeda

1
Тут можна скористатися exprкомандою
cli__

4
Ось один для Posix оболонок: stackoverflow.com/questions/2829613 / ...
sehe

Відповіді:


3648

Відповідь Маркуса (* підстановки) можна використовувати і поза заявою справи, якщо ви використовуєте подвійні дужки:

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 знайдено
Orwellophile

12
@Orwellophile Обережно! Ви можете опустити лише подвійні лапки в першому аргументі на [[. Дивіться ideone.com/ZSy1gZ
nyuszika7h

611

Якщо ви віддаєте перевагу підходу регулярного вираження:

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/FAQ E14) . Напевно, найкраще призначити змінну (використовуючи лапки), а потім порівняти. re="My s"; if [[ $string =~ $re ]]
Ось так

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;
Douwe van der Leest

356

Я не впевнений у використанні оператора if, але ви можете отримати подібний ефект із заявою:

case "$string" in 
  *foo*)
    # Do stuff
    ;;
esac

76
Це, мабуть, найкраще рішення, оскільки воно є портативним для передачі оболонок. (aka no bashism)
технозавр

25
@technosaurus Мені здається дивним критикувати "башизм" у питанні, яке має лише bash tag :)
ПП

39
@PP Це не стільки критика, скільки перевага більш універсального рішення перед більш обмеженим. Будь ласка, врахуйте, що через роки люди (як я) зупиняться, щоб шукати цю відповідь, і, можливо, з задоволенням знайдуть ту корисну в більш широкому обсязі, ніж оригінальне питання. Як кажуть у світі з відкритим кодом: "вибір хороший!"
Карл Смотрич

2
@technosaurus, FWIW [[ $string == *foo* ]]також працює у деяких версіях, сумісних з POSIX (наприклад, /usr/xpg4/bin/shна Solaris 10) та ksh (> = 88)
maxschlepzig

3
Зола Busybox не обробляє зірочки в [[... case-switch працював!
Рей Фосс

232

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
Це було б ще краще, якщо ви зможете придумати якийсь спосіб ввести це у функцію.
Eero Aaltonen

2
@EeroAaltonen Як знайти мою (нову додану) функцію?
Ф. Хаурі

2
Я знаю! знайти. -назви "*" | xargs grep "myfunc" 2> / dev / null
яєчники

6
Це чудово, адже це так сумісно. Однак одна помилка: вона не працює, якщо рядок сіна порожній. Правильна версія була б string_contains() { [ -z "${2##*$1*}" ] && [ -n "$2" -o -z "$1" ]; } заключною думкою: чи порожня рядок містить порожню рядок? Версія вище речей так (через -o -z "$1"частину).
Sjlver

3
+1. Дуже добре! Для мене я змінив замовлення stringContain () {[-z "$ {1 ## * $ 2 *}"] && [-z "$ 2" -o -n "$ 1"]; }; "Шукати, де", "Знайти що". Робота в зайнятому ящику. Прийнята відповідь вище не працює у зайнятій скриньці.
користувач3439968

148

Вам слід пам’ятати, що сценарій оболонки - це менше мови та більше набору команд. Інстинктивно ви думаєте, що ця "мова" вимагає, щоб ви слідували ifa [чи 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параметр змушує греп нічого не виводити, оскільки ми хочемо лише повернути код. <<<змушує оболонку розширювати наступне слово і використовувати його як вхід до команди, одно <<рядкову версію документа тут (я не впевнений, стандартний чи башизм).


7
їх називають тут рядками (3.6.7) Я вважаю, що це башизм
alex.pilon

10
можна також скористатись процесною if grep -q foo <(echo somefoothing); then
заміною

Зауважте, що echoце нерепортажно, якщо ви передаєте змінну, використовуйте printf '%s' "$stringнатомість.
nyuszika7h

5
Вартість цього коштує дуже дорого: роблять grep -q foo <<<"$mystring"імлі 1 вилка, а це башизм та echo $mystring | grep -q fooімлі 2 вилки (одна для труби, а друга для бігу /path/to/grep)
Ф. Хаурі

1
@BrunoBronosky echoбез прапорців може все-таки мати несподівані проблеми з переносністю, якщо рядок аргументу містить послідовності зворотної косої риски. echo "nope\c"Очікується, що на деяких платформах буде працювати, як echo -e "nope"на деяких інших. printf '%s' "nope"vsprintf '%s\n' 'nope\c'
трійка

92

Найкраще прийнята відповідь, але оскільки це існує більше, ніж один спосіб, це ще одне рішення:

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

${var/search/replace}це $varз першим примірником searchзамінено replace, якщо він знайдений (це не змінює $var). Якщо ви намагаєтеся замінити fooнічим, а рядок змінився, то, очевидно, fooзнайшли.


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'

Заміна тестування щоразу:

[[ $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 грепсів передбачувано болісно! Старе правило щодо використання зовнішніх утиліт без потреби справедливо.


4
Акуратний орієнтир. Переконав мене використовувати [[ $b == *$a* ]].
Божевільний фізик

2
Якщо я читаю це правильно, caseвиграє з найменшим загальним споживанням часу. $b in *$aОднак вам не вистачає зірочки . Я отримую трохи швидші результати, [[ $b == *$a* ]]ніж для caseвиправлення помилки, але це, звичайно, може залежати і від інших факторів.
трійка

1
ideone.com/5roEVt мій експеримент із виправленими додатковими помилками та тестування для іншого сценарію (де рядок насправді відсутній у довшій рядку). Результати багато в чому схожі; [[ $b == *$a* ]]швидко і caseмайже так само швидко (і приємно сумісний з POSIX).
трійка

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

Я думаю, цей стиль трохи класичніший - менш залежний від особливостей оболонки Баша.

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

Примітка. У тісному циклі цей код буде набагато повільніше, ніж використання внутрішніх функцій оболонки Bash, оскільки один (або два) окремі процеси будуть створені та з'єднані за допомогою труб.


5
... але ОП не говорить, яка версія баш; наприклад, старші баші (такі, як часто виникає соняш) можуть не включати ці нові функції басу. (Я зіткнувся з цією точною проблемою (відповідність шаблону баш не реалізована) на solaris w / bash 2.0)
Майкл

2
echoнерепортаж, ви повинні використовувати це printf '%s' "$haystackзамість цього.
nyuszika7h

2
Ні, просто уникайте echoвзагалі нічого, крім прямого тексту, без уникнень, які не починаються з -. Це може працювати для вас, але це не портативно. Навіть bash's 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, як "випадок" $ string "у" відповіді, наданій Маркусом , але її читати трохи простіше, ніж відповідь на випадок справи. Також зауважте, що це буде набагато набагато повільніше, ніж використання заяви справи. Як зазначив Пол, не використовуйте це в циклі.



9
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"

Додам, що echo "Couldn't findвислів наприкінці - приємна хитрість повернути 0 статусів виходу для цих відповідних команд.
nicodjimenez

@nicodjimenez ви більше не можете орієнтуватися на статус виходу за допомогою цього рішення. Стан виходу поглинається повідомленнями про стан ...
Jahid

1
Це саме те, що я мав на увазі ... Якщо у вас немає, || echo "Couldn't find"ви повернете статус виходу з помилки, якщо немає відповідності, чого ви, можливо, не хочете, якщо ви працюєте з конвеєром CI, наприклад, де потрібно, щоб усі команди поверталися статуси виходу без помилок
nicodjimenez

9

Одне:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'

2
expr- це одна з тих утиліт, які носять швейцарські армії, які зазвичай можуть робити все, що вам потрібно зробити, як тільки ви зрозумієте, як це зробити, але колись це буде здійснено, ви ніколи не можете згадати, чому і як це робить те, що робить, тож ви ніколи не торкайтеся його знову і сподівайтеся, що він ніколи не перестане робити те, що робить.
Майкл

@AloisMahdal Я ніколи не проголосував, я просто постулював над тим, чому давали голоси. Застереження коментар. Я рідко використовую expr, коли портативність перешкоджає використанню bash (наприклад, непослідовна поведінка у старих версіях), tr (непослідовно скрізь) або sed (іноді занадто повільно). Але з особистого досвіду, кожного разу, коли перечитую ці expr-изми, я мушу повертатися на сторінку чоловіка. Отже, я б просто прокоментував, що кожне використання exprкоментується ...
michael

1
Був час, коли все, що у вас було, було оригінальною оболонкою Борна. У ньому бракувало деяких часто потрібних функцій, тому інструменти для їх виконання подобалися exprта testбули реалізовані. У цей день і вік зазвичай є кращі інструменти, багато з яких вбудовані в будь-яку сучасну оболонку. Я здогадуюсь test, все ще там висить, але, здається, ніхто не пропав expr.
трійка

6

Мені подобається sed.

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


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 НІ
elyase

Я майже впевнений, що 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
Це відповідь?
кодовий ліс

піднести чому турбуватися, щоб дізнатися, як це робить Bash, коли греп, набагато потужніший, швидше за все, буде доступний. також розгорніть його трохи далі, зіставляючи зі списком шаблонів: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!'

Зверніть увагу на єдиний знак рівності!


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

Спробуйте oobash.

Це бібліотека рядків у стилі OO для Bash 4. У ній є підтримка німецьких умлаутів. Це написано на Баші.

Багато функцій: -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". Він знаходиться у файлі archell_str.sh GitHub. 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


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.