Как определить, является ли строка подстрокой другого в bash?

49

Я хочу видеть, находится ли строка внутри части другой строки.
например:

'ab' in 'abc' -> true
'ab' in 'bcd' -> false

Как я могу сделать это в условном сценарии bash?

Lucio
источник

Ответы:

27

Вы можете использовать форму , ${VAR/subs}где VARсодержится больше строки и subsподстрока ваши пытаются найти:

my_string=abc
substring=ab
if [ "${my_string/$substring}" = "$my_string" ] ; then
  echo "${substring} is not in ${my_string}"
else
  echo "${substring} was found in ${my_string}"
fi

Это работает, потому что ${VAR/subs}равно $VARпервому вхождению строки subs, но если $VARоно не содержит слова, subsоно не будет изменено.

Эдвин
источник
Я думаю, что вы должны изменить последовательность echoзаявлений. Потому что я получаюab is not in abc
Лусио
Ты прав! : P
Эдвин
Ммм .. Нет, скрипт неверный. Как то, что я получаю ab was found in abc, но если я использую, substring=zя получаюz was found in abc
Lucio
1
Теперь я получаю ab is not in abc. Но z was found in abc. Это смешно: D
Лусио
1
Duh! Отголоски были прямо в начале этого! XD
Эдвин
47

[[ "bcd" =~ "ab" ]]
[[ "abc" =~ "ab" ]]

квадратные скобки предназначены для теста, и поскольку это двойные квадратные скобки, могут быть использованы некоторые дополнительные тесты =~.

Таким образом, вы можете использовать эту форму что-то вроде

var1="ab"
var2="bcd"
if [[ "$var2" =~ "$var1" ]]; then
    echo "pass"
else
    echo "fail"
fi

Редактировать: исправлено "= ~", перевернуто.

скромный
источник
1
Я получаю failс такими параметрами:var2="abcd"
Лусио
3
@Lucio Правильно [[ $string =~ $substring ]]. Я обновил ответ.
Эрик Карвалью
12

Использование шаблонов имен файлов bash (также называемых шаблонами "glob")

substr=ab
[[ abc == *"$substr"* ]] && echo yes || echo no    # yes
[[ bcd == *"$substr"* ]] && echo yes || echo no    # no
Гленн Джекман
источник
if [["$ JAVA_OPTS"! = "-XX: + UseCompressedOops" ]]; затем экспортируйте JAVA_OPTS = "$ JAVA_OPTS -XX: + UseCompressedOops"; фантастика
Майк Слинн
10

Следующие два подхода будут работать в любой POSIX-совместимой среде, а не только в bash:

substr=ab
for s in abc bcd; do
    if case ${s} in *"${substr}"*) true;; *) false;; esac; then
        printf %s\\n "'${s}' contains '${substr}'"
    else
        printf %s\\n "'${s}' does not contain '${substr}'"
    fi
done
substr=ab
for s in abc bcd; do
    if printf %s\\n "${s}" | grep -qF "${substr}"; then
        printf %s\\n "'${s}' contains '${substr}'"
    else
        printf %s\\n "'${s}' does not contain '${substr}'"
    fi
done

Оба вышеприведенных вывода:

'abc' contains 'ab'
'bcd' does not contain 'ab'

Преимущество первого состоит в том, что он не порождает отдельный grepпроцесс.

Обратите внимание, что я использую printf %s\\n "${foo}"вместо echo "${foo}"потому что echoможет искажать, ${foo}если он содержит обратную косую черту.

Ричард Хансен
источник
Первая версия отлично подходит для поиска подстроки имени монитора в списке xrandrимен мониторов, хранящихся в переменной. +1 и добро пожаловать в 1K Rep Club :)
WinEunuuchs2Unix
6

оператор оболочки

Это самое портативное решение, будет работать даже на старых оболочках Bourne и Korn.

#!/bin/bash
case "abcd" in
    *$1*) echo "It's a substring" ;;
    *) echo "Not a substring" ;;
esac

Образец прогона:

$ ./case_substr.sh "ab"                                                                                           
It's a substring
$ ./case_substr.sh "whatever"                                                                                     
Not a substring

Обратите внимание, что вам не нужно специально использовать, echoвы можете использовать exit 1и exit 0для обозначения успеха или неудачи.

То, что мы могли бы также сделать, это создать функцию (которая может использоваться в больших сценариях при необходимости) с конкретными возвращаемыми значениями (0 при совпадении, 1 при отсутствии совпадения):

$ ./substring_function.sh                                  
ab is substring

$ cat substring_function.sh                                
#!/bin/sh

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

main(){
   if is_substring "ab" "abcdefg"
   then
       echo "ab is substring"
   fi
}

main $@

Grep

$ grep -q 'ab' <<< "abcd" && echo "it's a substring" || echo "not a substring"                                    
it's a substring

Этот конкретный подход полезен для операторов if-else в bash. Также в основном портативный

AWK

$ awk '$0~/ab/{print "it is a substring"}' <<< "abcd"                                                             
it is a substring

питон

$ python -c 'import sys;sys.stdout.write("it is a substring") if "ab" in sys.stdin.read() else exit(1)' <<< "abcd"
it is a substring

Рубин

$ ruby -e ' puts "is substring" if  ARGV[1].include? ARGV[0]'  "ab" "abcdef"                                             
is substring
Сергей Колодяжный
источник
+1 для того, чтобы идти выше и выше всех остальных. Я заметил здесь и на других сайтах обмена стека нет ответа возвращает смещение подстроки в строке. Что является сегодняшней миссией :)
WinEunuuchs2Unix
@ WinEunuuchs2Unix Собираетесь сделать это в Bash?
Сергей Колодяжный
Да и нет. Я делаю проект во Франкенштейне, где python get получает все метаданные сообщений gmail.com, bash анализирует их и представляет список GUI с детализацией. Я нашел ответ, хотя здесь: stackoverflow.com/questions/5031764/…
WinEunuuchs2Unix
@ WinEunuuchs2Unix ОК. Звучит интересно. Я лично предпочел бы разобрать все в Python. В нем гораздо больше возможностей для обработки текста, чем в bash.
Сергей Колодяжный
Я знаю твои предпочтения около двух лет и уважаю их. Но я просто изучаю Python и заставляю его работать в нем, мне кажется обременительным. Не говоря уже о всей обработке массива, с которой я уже знаком в bash. Но, по крайней мере, я написал свой первый скрипт на python, чтобы высосать все из google.com google.com в плоский файл Linux, верно? :)
WinEunuuchs2Unix
5

Имейте в виду [[и ":

[[ $a == z* ]]   # True if $a starts with an "z" (pattern matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).

[ $a == z* ]     # File globbing and word splitting take place.
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).

Поэтому, как сказал @glenn_jackman, учтите, что если вы заключите весь второй член в двойные кавычки, он переключит тест на буквальное соответствие.

Источник: http://tldp.org/LDP/abs/html/comparison-ops.html

Campa
источник
4

Аналогичен ответу Эдвина, но с улучшенной переносимостью для posix & ksh и менее шумным, чем у Ричарда:

substring=ab

string=abc
if [ "$string" != "${string%$substring*}" ]; then
    echo "$substring IS in $string"
else
    echo "$substring is NOT in $string"
fi

string=bcd
if [ "$string" != "${string%$substring*}" ]; then
    echo "$string contains $substring"
else
    echo "$string does NOT contain $substring"
fi

Выход:

abc contains ab
bcd does NOT contain ab
laubster
источник