Teste se uma string contém uma substring

Eu tenho o código

file="JetConst_reco_allconst_4j2t.png" if [[ $file == *_gen_* ]]; then echo "True" else echo "False" fi 

Eu testo se file contém “gen”. A saída é “False”. Legal!

O problema é quando substituo “gen” por uma variável testseq:

file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file == *_$testseq_* ]]; then echo "True" else echo "False" fi 

Agora a saída é “True”. Como isso poderia ser? Como resolver o problema?

Comentários

Resposta

Você precisa interpolar o $testseq variável com uma das seguintes maneiras:

  • $file == *_"$testseq"_* (aqui $testseq considerado como uma string fixa)

  • $file == *_${testseq}_* (aqui $testseq considerado como um padrão).

Ou _ imediatamente após o nome da variável “s será considerado como parte da variável” s nome (é um caractere válido em um nome de variável).

Comentários

  • Resposta correta, pois se aplica ao OP, mas não é portátil . (Esta não é uma crítica à resposta fornecida, apenas um aviso aos leitores). 😉

Resposta

Use a operação =~ ou para fazer comparações de expressões regulares:

#!/bin/bash file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file =~ $testseq ]]; then echo "True" else echo "False" fi 

Dessa forma, ele comparará se $file tiver $testseq em seu conteúdo.

user@host:~$ ./string.sh False 

Se eu mudar testseq="Const":

user@host:~$ ./string.sh True 

Mas, tome cuidado com o que você alimenta $testseq. Se a string nele representa de alguma forma um regex (como [0-9] por exemplo), há uma chance maior de acionar uma “correspondência”.

Referência :

Comentários

  • Parece que esta resposta é para " bash " apenas

Resposta

file="JetConst_reco_allconst_4j2t.png" testseq="gen" case "$file" in *_"$testseq"_*) echo "True" ;; *) echo "False" esac 

Usar case ... esac é uma das maneiras mais simples de realizar uma correspondência de padrão de forma portátil. Funciona como uma instrução “switch” em outros idiomas (bash, zsh e ksh93 também permite que você faça fall-through de várias maneiras incompatíveis). Os padrões usados são os padrões de globbing de nome de arquivo padrão.

O problema que você está tendo é devido ao fato de que _ é um caractere válido em um nome de variável. O shell, portanto, verá *_$testseq_* como “*_ seguido pelo valor da variável $testseq_ e um * “. A variável $testseq_ é indefinida, então ela será expandida para uma string vazia e você acabará com *_*, que obviamente corresponde a $file valor que você tem. Você pode esperar obter True, desde que o nome do arquivo em $file contenha pelo menos um sublinhado.

Para adequadamente delimite o nome da variável, use "..." em torno da expansão: *_"$testseq"_*. Isso usaria o valor da variável como uma string. Se você quiser usar o valor da variável como um padrão , use *_${testseq}_* em vez disso.

Outra solução rápida é incluir o sublinhados no valor de $testseq:

testseq="_gen_" 

e, em seguida, basta usar *"$testseq"* como o padrão (para uma comparação de string).

Comentários

  • Portanto, o shell estará procurando por uma variável $ testseq_ e não encontrará e substitua-o por uma string vazia.
  • @Viesturs Que ' s é o cerne da questão, sim.
  • Para um a pesquisa de substring deve ser *"$testseq"* para case como para [[...]] (exceto para zsh, a menos que você enable globsubst)
  • Mais simples do que ?
  • @Isaac Em termos de leitura e compreensão do que ' está acontecendo, sim. É ' também fácil estender um teste com mais casos de teste sem obter um " if-then-elif-then-elif " espaguete. Embora teste uma única string, a maneira como você mostra (se uma string desaparece em uma substituição) é mais curta.

Resposta

Para a forma portátil de testar se uma string contém uma substring, use:

file="JetConst_reco_allconst_4j2t.png"; testseq="gen" [ "${file##*$testseq*}" ] || echo True Substring is present 

Ou "${file##*"$testseq"*}" para evitar interpretar caracteres glob em testseq.

Comentários

  • Você ' d precisa de algo como [" $ {file ## * $ testseq *} "! = " $ file " ] porque no traço que é Remover o maior padrão de prefixo.
  • Não, @NoelGrandin não há mudança na maioria dos shells (incluindo o traço), o Padrão do maior prefixo será a string inteira se o valor do subpadrão da variável ($testseq) estiver contido no valor $file. Tente: dash -c 'file="JetConst_reco_allconst_4j2t.png"; testseq="reco"; echo "=${file##*"$testseq"*}="' para confirmar que o traço removerá toda a string.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *