Como verificar se uma string contém uma substring no Bash

2572

Eu tenho uma string no Bash:

string="My string"

Como posso testar se ele contém outra string?

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

Onde ??está meu operador desconhecido. Eu uso eco e grep?

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

Isso parece um pouco desajeitado.

davidsheldon
fonte
4
Olá, se strings vazias são falsas, por que você considera desajeitado? Foi a única maneira que funcionou para mim, apesar das soluções propostas.
Ericson.cepeda
1
Você pode usar o exprcomando aqui
cli__ 02/02
4
Aqui está um para shells posix: stackoverflow.com/questions/2829613/…
sehe

Respostas:

3654

Você também pode usar a resposta de Marcus (* curingas) fora de uma declaração de caso, se usar colchetes duplos:

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

Observe que os espaços na corda da agulha precisam ser colocados entre aspas duplas, e os *curingas devem estar do lado de fora. Observe também que um operador de comparação simples é usado (ou seja ==), não o operador regex =~.

Adam Bellaire
fonte
127
Observe também que você pode reverter a comparação mudando para! = No teste. Obrigado pela resposta!
Quinn Taylor
63
@ Jonik: Você pode estar perdendo o shebang ou tê-lo como #!/bin/sh. Tente em #!/bin/bashvez disso.
Pausado até novo aviso.
10
Deixe um espaço entre os colchetes e o conteúdo.
Paul Price
17
Você não precisa citar variáveis ​​dentro de [[]]. Isso também funcionará: [[string == $ agulha ]] && eco encontrado
Orwellophile
13
@Orwellophile Careful! Você só pode omitir as aspas duplas no primeiro argumento para [[. Veja como ideone.com/ZSy1gZ
nyuszika7h
611

Se você preferir a abordagem regex:

string='My string';

if [[ $string =~ "My" ]]
then
   echo "It's there!"
fi
Matt Tardiff
fonte
2
Teve que substituir um regex egrep em um script bash, isso funcionou perfeitamente!
Blast_hardcheese
114
O =~operador já pesquisa uma sequência inteira para uma correspondência; os .*aqui são estranhos. Além disso, as citações são geralmente preferível barras invertidas:[[ $string =~ "My s" ]]
bukzor
16
@bukzor As citações pararam de funcionar aqui a partir do Bash 3.2+: tiswww.case.edu/php/chet/bash/FAQ E14) . Provavelmente, é melhor atribuir a uma variável (usando aspas) e comparar. Assim:re="My s"; if [[ $string =~ $re ]]
seanf
36
Teste se NÃO contém uma sequência: if [[ ! "abc" =~ "d" ]]é verdadeira.
KrisWebDev
1
Observe que a ordem na qual o teste ocorre é importante. A saída da seguinte linha de código será encaminhada 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

Não tenho certeza sobre o uso de uma instrução if, mas você pode obter um efeito semelhante com uma instrução case:

case "$string" in 
  *foo*)
    # Do stuff
    ;;
esac
Marcus Griep
fonte
76
Esta é provavelmente a melhor solução, pois é portátil para cartuchos posix. (aka não bashisms)
technosaurus
25
@technosaurus acho que é um pouco estranho para criticar "Bashismo" em uma questão que tem apenas tag festa :)
PP
39
@PP Não é tanto uma crítica quanto a preferência de uma solução mais universal do que uma mais limitada. Por favor, considere que, anos mais tarde, pessoas (como eu) vão parar para procurar esta resposta e podem ter prazer em encontrar uma que seja útil em um escopo mais amplo do que a pergunta original. Como se costuma dizer no mundo do código aberto: "a escolha é boa!"
Carl Smotricz
2
@technosaurus, FWIW [[ $string == *foo* ]]também funciona em algumas versões sh compatível com POSIX (por exemplo, /usr/xpg4/bin/shno Solaris 10) e ksh (> = 88)
maxschlepzig
3
A cinza do Busybox não lida com asteriscos [[... o comutador de caixa funcionou!
Ray Foss
232

stringContain variantes (compatível ou independente de maiúsculas e minúsculas)

Como essas respostas do Stack Overflow falam principalmente sobre o Bash , publiquei uma função Bash independente do caso na parte inferior deste post ...

De qualquer forma, existe o meu

Resposta compatível

Como já existem muitas respostas usando os recursos específicos do Bash, existe uma maneira de trabalhar com shells com recursos mais ruins , como o BusyBox :

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

Na prática, isso poderia dar:

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

Isso foi testado em Bash, Dash , KornShell ( ksh) e ash (BusyBox), e o resultado é sempre:

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

Em uma função

Conforme solicitado por @EeroAaltonen, aqui está uma versão da mesma demonstração, testada sob as mesmas conchas:

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
}

Então:

$ 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'.

Aviso: você precisa escapar ou colocar aspas duplas e / ou aspas duplas:

$ 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'.

Função simples

Isso foi testado no BusyBox, Dash e, é claro, no Bash:

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

Então agora:

$ 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

... Ou se a string enviada pudesse estar vazia, como apontado por @Sjlver, a função se tornaria:

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

ou conforme sugerido pelo comentário de Adrian Günter , evitando -ointerrupções:

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

Função final (simples):

E invertendo os testes para torná-los potencialmente mais rápidos:

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

Com cadeias vazias:

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

Independente de maiúsculas e minúsculas (somente Bash!)

Para testar seqüências de caracteres sem o cuidado de maiúsculas e minúsculas, basta converter cada sequência em minúsculas:

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

Verifica:

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
F. Hauri
fonte
1
Isso seria ainda melhor, se você puder descobrir uma maneira de colocar isso em uma função.
Eero Aaltonen
2
@EeroAaltonen Como você encontra minha função (nova adicionada)?
F. Hauri
2
Eu sei! encontrar . -name "*" | xargs grep "myfunc" 2> / dev / null
eggmatters 15/07/14
6
Isso é maravilhoso porque é muito compatível. Um erro, no entanto: não funciona se a cadeia de feno estiver vazia. A versão correta seria string_contains() { [ -z "${2##*$1*}" ] && [ -n "$2" -o -z "$1" ]; } um pensamento final: a string vazia contém a string vazia? A versão acima das coisas sim (por causa da -o -z "$1"parte).
Sjlver
3
+1. Muito bom! Para mim, mudei a ordem stringContain () {[-z "$ {1 ## * $ 2 *}"] && [-z "$ 2" -o -n "$ 1"]; }; "Procure onde" "Encontre o que". Trabalhar no busybox. A resposta aceita acima não funciona no busybox.
user3439968
149

Você deve se lembrar que o script de shell é menos uma linguagem e mais uma coleção de comandos. Instintivamente, você acha que esse "idioma" exige que você siga um ifcom um [ou um [[. Ambos são apenas comandos que retornam um status de saída indicando sucesso ou falha (como todos os outros comandos). Por esse motivo, eu usaria grep, e não o [comando.

Apenas faça:

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

Agora que você está pensando ifem testar o status de saída do comando a seguir (completo com ponto e vírgula), por que não reconsiderar a origem da string que está testando?

## 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
#...

A -qopção faz com que o grep não produza nada, pois queremos apenas o código de retorno. <<<faz com que o shell expanda a próxima palavra e use-a como entrada para o comando, uma versão em uma linha do <<documento aqui (não tenho certeza se isso é padrão ou um bashismo).

Mark Baker
fonte
7
eles são chamados aqui cordas (3.6.7) Eu acredito que é Bashismo
alex.pilon
10
pode-se também usar Processo de Substituição if grep -q foo <(echo somefoothing); then
larsr
Observe que não echoé portável, se você estiver passando uma variável, use printf '%s' "$string.
nyuszika7h
5
O custo deste é muito caro: fazendo grep -q foo <<<"$mystring"implie 1 garfo e é Bashismo e echo $mystring | grep -q fooimplie 2 garfos (um para o tubo e o segundo para executar /path/to/grep)
F. Hauri
1
@BrunoBronosky echosem sinalizadores ainda pode ter problemas inesperados de portabilidade se a sequência de argumentos contiver sequências de barra invertida. echo "nope\c"é esperado em algumas plataformas para funcionar como echo -e "nope"em outras. printf '%s' "nope"vsprintf '%s\n' 'nope\c'
tripleee 12/04
92

A resposta aceita é a melhor, mas como há mais de uma maneira de fazê-lo, aqui está outra solução:

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

${var/search/replace}é $varcom a primeira instância de searchsubstituído por replace, se for encontrado (não muda $var). Se você tentar substituir foopor nada, e a cadeia de caracteres mudou, então obviamente foofoi encontrado.

efémero
fonte
5
solução do ephemient acima:> `if [" $ string "! =" $ {string / foo /} "]; então ecoa "Está aí!" fi` é útil ao usar a casca de cinzas do BusyBox . A solução aceita não funciona com o BusyBox porque algumas expressões regulares do bash não são implementadas.
TPoschel
1
a desigualdade da diferença. Pensamento bastante estranho! Eu adoro isso
nitinr708
1
a menos que sua string seja 'foo'
venimus 12/07/19
Eu mesmo escrevi essa mesma solução (porque meu intérprete não aceitaria as respostas principais) e depois procurei uma melhor, mas achei isso!
BuvinJ
56

Portanto, existem muitas soluções úteis para a pergunta - mas qual é mais rápida / utiliza o menor número de recursos?

Testes repetidos usando esse quadro:

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

Substituindo TEST toda vez:

[[ $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 estava na resposta de F. Houri)

E para rir:

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

Portanto, a opção de substituição simples vence previsivelmente, seja em um teste prolongado ou em um caso. O estojo é portátil.

A canalização para 100000 greps é previsivelmente dolorosa! A regra antiga sobre o uso de utilitários externos sem necessidade é verdadeira.

Paul Hedderly
fonte
4
Referência pura. Me convenceu a usar [[ $b == *$a* ]].
May Physicist
2
Se estou lendo isso corretamente, caseganha com o menor consumo de tempo geral. Você está perdendo um asterisco depois $b in *$a. Eu obtenho resultados um pouco mais rápidos do [[ $b == *$a* ]]que casecom o bug corrigido, mas também pode depender de outros fatores, é claro.
Tripleee
1
O ideone.com/5roEVt tem meu experimento com alguns bugs adicionais corrigidos e testa um cenário diferente (onde a string realmente não está presente na string mais longa). Os resultados são amplamente semelhantes; [[ $b == *$a* ]]é rápido e caseé quase tão rápido (e agradavelmente compatível com POSIX).
tripleee
28

Isso também funciona:

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

E o teste negativo é:

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

Suponho que esse estilo seja um pouco mais clássico - menos dependente dos recursos do shell Bash.

O --argumento é pura paranóia POSIX, usada para proteger contra seqüências de entrada semelhantes a opções, como --abcou -a.

Nota: Em um loop restrito, esse código será muito mais lento do que usar os recursos internos do shell Bash, pois um (ou dois) processos separados serão criados e conectados por meio de pipes.

kevinarpe
fonte
5
... mas o OP não diz qual versão do bash; por exemplo, o bash mais antigo (como o solaris costuma incluir) pode não incluir esses recursos mais recentes do bash. (Eu executar para esse problema exato (bash correspondência de padrões não implementado) no Solaris w / bash 2.0)
michael
2
echonão é portável, você deve estar usando printf '%s' "$haystack.
nyuszika7h
2
Não, apenas evite echocompletamente qualquer coisa, exceto texto literal, sem escapes que não iniciem com a -. Pode funcionar para você, mas não é portátil. Até o bash echose comportará de maneira diferente, dependendo de a xpg_echoopção estar definida. PS: Esqueci de fechar as aspas duplas no meu comentário anterior.
usar o seguinte código
1
@kevinarpe Não tenho certeza, --não está listado na especificação POSIX paraprintf , mas você deve usar printf '%s' "$anything"assim mesmo, para evitar problemas se $anythingcontiver um %caractere.
nyuszika7h
1
@kevinarpe Com base nisso, provavelmente é.
nyuszika7h
21

Bash 4+ exemplos. Nota: não usar aspas causará problemas quando as palavras contiverem espaços, etc. Sempre cite no Bash, IMO.

Aqui estão alguns exemplos do Bash 4+:

Exemplo 1, verifique 'yes' na string (não faz distinção entre maiúsculas e minúsculas):

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

Exemplo 2, verifique 'yes' na string (não faz distinção entre maiúsculas e minúsculas):

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

Exemplo 3, verifique se 'yes' na string (diferencia maiúsculas de minúsculas):

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

Exemplo 4, verifique se 'yes' na string (diferencia maiúsculas de minúsculas):

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

Exemplo 5, correspondência exata (diferencia maiúsculas de minúsculas):

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

Exemplo 6, correspondência exata (sem distinção entre maiúsculas e minúsculas):

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

Exemplo 7, correspondência exata:

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

Exemplo 8, correspondência de curinga .ext (sem distinção entre maiúsculas e minúsculas):

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

Aproveitar.

Mike Q
fonte
17

Que tal agora:

text="   <tag>bmnmn</tag>  "
if [[ "$text" =~ "<tag>" ]]; then
   echo "matched"
else
   echo "not matched"
fi
bn.
fonte
2
= ~ é para correspondência de expressão regular, portanto, muito poderoso para o objetivo do OP.
16

Como Paulo mencionou em sua comparação de desempenho:

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

Isso é compatível com POSIX, como o 'case "$ string" na resposta fornecida por Marcus , mas é um pouco mais fácil de ler do que a resposta da instrução de caso. Observe também que isso será muito mais lento do que usar uma declaração de caso. Como Paulo apontou, não o use em loop.

Samuel
fonte
11

Essa resposta de estouro de pilha foi a única a capturar espaço e trace caracteres:

# For null cmd arguments checking   
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found
Yordan Georgiev
fonte
É uma resposta para essa mesma pergunta.
Peter Mortensen
9
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"
Jahid
fonte
Acrescentarei que a echo "Couldn't findinstrução no final é um bom truque para retornar 0 status de saída para esses comandos correspondentes.
Nicodjimenez 16/10
@nicodjimenez, você não pode mais segmentar o status de saída com esta solução. O status de saída é engolido pelas mensagens de status ...
Jahid
1
Foi exatamente isso que eu quis dizer ... Se você não tiver || echo "Couldn't find", retornará um status de saída de erro se não houver correspondência, o que talvez você não queira se estiver executando um pipeline de IC, por exemplo, onde deseja que todos os comandos retornem status de saída sem erro
nicodjimenez 17/10
9

Um é:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'
chemila
fonte
2
expré um daqueles utilitários de canivete suíço que geralmente pode fazer o que você precisa fazer, depois de descobrir como fazê-lo, mas uma vez implementado, você nunca consegue se lembrar por que ou como está fazendo o que está fazendo, então você nunca toque novamente e espere que nunca pare de fazer o que está fazendo.
10133 Michael
@AloisMahdal Eu nunca votei para baixo, apenas estou postulando por que os votos negativos foram dados. Um comentário de advertência. Eu uso expr, em raras ocasiões, quando a portabilidade impede o uso do bash (por exemplo, comportamento inconsistente em versões mais antigas), tr (inconsistente em todos os lugares) ou sed (às vezes muito lento). Mas por experiência pessoal, sempre que reler esses exprisismos, tenho que voltar à página de manual. Então, gostaria apenas de comentar que todo uso de exprser comentado ...
Michael
1
Houve um tempo em que tudo que você tinha era o shell Bourne original. Faltavam alguns recursos geralmente necessários, portanto, ferramentas como expre testforam implementadas para executá-los. Hoje em dia, geralmente existem ferramentas melhores, muitas delas embutidas em qualquer shell moderno. Acho que testainda está lá, mas parece que ninguém está faltando expr.
Tripleee
6

Eu gosto de sed.

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

Editar, Lógica:

  • Use sed para remover a instância da substring da string

  • Se a nova string for diferente da antiga, existe substring

passeio
fonte
2
Por favor, adicione alguma explicação. Transmitir a lógica subjacente é mais importante do que apenas dar o código, porque ajuda o OP e outros leitores de corrigir isso e questões semelhantes a si mesmos
Zulan
5

grep -q é útil para esse fim.

O mesmo usando awk:

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

Resultado:

Não encontrado

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

Resultado:

Encontrado

Fonte original: http://unstableme.blogspot.com/2008/06/bash-search-letter-in-string-awk.html

nyuszika7h
fonte
3
echonão é portável, você deve estar usando printf '%s' "$string". Estou editando a resposta porque o usuário não parece mais existir.
nyuszika7h
De que maneira echonão é portátil, @ nyuszika7h?
starbeamrainbowlabs
5

Descobri que precisava dessa funcionalidade com bastante frequência, por isso estou usando uma função de shell caseira da .bashrcmesma maneira que permite reutilizá-la quantas vezes for necessário, com um nome fácil de lembrar:

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

Para testar se $string1(digamos, abc ) está contido em $string2(digamos, 123abcABC ), só preciso executar stringinstring "$string1" "$string2"e verificar o valor de retorno, por exemplo

stringinstring "$str1" "$str2"  &&  echo YES  ||  echo NO
Kurt Pfeifle
fonte
[["$ str" == $ substr ]] && eco SIM || echo NO
elyase
Tenho certeza de que o xhack é necessário apenas para conchas muito antigas.
nyuszika7h
5

Meu arquivo .bash_profile e como usei o grep:

Se a variável de ambiente PATH incluir meus dois bindiretórios, não os anexe.

# .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
Leslie Satenstein
fonte
1
Isso é uma resposta?
precisa saber é o seguinte
voto positivo. por que se preocupar em aprender como o Bash faz isso quando grep, muito mais poderoso, é mais do que provável que estará disponível. também estendê-lo um pouco mais longe, a comparação com uma lista de padrões: grep -q -E 'pattern1|...|patternN'.
Mohamed Bana
4

Extensão da pergunta respondida aqui Como saber se uma string contém outra string no POSIX sh? :

Esta solução funciona com caracteres especiais:

# 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*"
Alex Skrypnyk
fonte
O teste contains "-n" "n"não funciona aqui, porque echo -nengolirá o -ncomo uma opção! Uma correção popular para isso é usar em seu printf "%s\n" "$string"lugar.
Joeytwiddle 12/12/19
perfeitamente, string resolvida continha espaços
dengApro 23/01
4

Como a pergunta POSIX / BusyBox é encerrada sem fornecer a resposta correta (IMHO), vou postar uma resposta aqui.

A resposta mais curta possível é:

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

ou

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

Observe que o hash duplo é obrigatório com algumas conchas ( ash). Acima avaliará [ stringvalue ]quando a substring não for encontrada. Não retorna erro. Quando a substring é encontrada, o resultado está vazio e é avaliado [ ]. Isso lançará o código de erro 1, pois a string é completamente substituída (devido a *).

A sintaxe mais curta e comum:

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

ou

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

Outro:

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

ou

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

Observe o único sinal de igual!

FifthAxiom
fonte
3

Correspondência exata de palavras:

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

if grep -E -q "\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
  then
    echo "It's there"
  fi
Eduardo Cuomo
fonte
3

Tente oobash.

É uma biblioteca de cadeias no estilo OO para o Bash 4. Possui suporte para tremas alemães. Está escrito em Bash.

Muitas funções estão disponíveis: -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, e -zfill.

Veja o exemplo contém :

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

oobash está disponível no Sourceforge.net .

andreas
fonte
2

Eu uso essa função (uma dependência não incluída, mas óbvia). Passa nos testes mostrados abaixo. Se a função retornar um valor> 0, a sequência foi encontrada. Você poderia facilmente retornar 1 ou 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
}
Ethan Post
fonte
O suspense! Qual é a dependência?
Peter Mortensen
A função "str_escape_special_characters". Está no arquivo arcshell_str.sh do GitHub. arcshell.io o levará até lá.
Ethan Post
0
msg="message"

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

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

check

Isso encontrará qualquer ocorrência de a ou b ou c

BobMonk
fonte
0

O exemplo genérico do palheiro de agulhas está seguindo com variáveis

#!/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
fonte