Teste se uma string contém uma substring

28

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". Nice!

O problema é quando eu 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 consertar o problema?

    
por Viesturs 13.06.2017 / 16:26

3 respostas

18

Você precisa interpolar a variável $testseq com uma das seguintes formas:

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

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

por 13.06.2017 / 16:33
17

Use o operador =~ para fazer comparações regulares de expressão:

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

Desta forma, irá comparar se $file tem $testseq no seu conteúdo.

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

Se eu alterar testseq="Const" :

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

Mas, tenha cuidado com o que você alimenta $testseq com. Se a string nela representar uma regex (como [0-9] , por exemplo), há mais chance de acionar uma "correspondência".

Referência :

por 13.06.2017 / 19:22
14
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 executar uma correspondência de padrão de maneira portátil. Ele funciona como uma instrução "switch" em outros idiomas ( bash e ksh93 também permite que você faça fall-through de várias maneiras). Os padrões utilizados são os padrões de globbing do 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 verá *_$testseq_* como " *_ seguido pelo valor da variável $testseq_ e * ". A variável $testseq_ é indefinida, então será expandida para uma string vazia, e você acaba com *_* , que obviamente corresponde. Portanto, você pode esperar obter True , desde que o nome do arquivo em $file contenha pelo menos um sublinhado.

Para delimitar adequadamente o nome da variável, use {...} em torno de seu nome: *_${testseq}_* .

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

testseq="_gen_"

e, em seguida, use apenas *$testseq* como padrão.

    
por 13.06.2017 / 16:35