Prueba si una cadena contiene una subcadena

40

Tengo el codigo

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

Pruebo si filecontiene "gen". El resultado es "Falso". ¡Agradable!

El problema es cuando sustituyo "gen" con una variable testseq:

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

Ahora el resultado es "Verdadero". ¿Como puede ser? ¿Como solucionar el problema?

Viesturs
fuente
Posible duplicado de la prueba

Respuestas:

25

Debe interpolar la $testseqvariable con una de las siguientes formas:

  • $file == *_"$testseq"_*(aquí $testseqconsiderado como una cadena fija)

  • $file == *_${testseq}_*(aquí $testseqconsiderado como un patrón).

O _inmediatamente después del nombre de la variable se tomará como parte del nombre de la variable (es un carácter válido en un nombre de variable).

RomanPerekhrest
fuente
Respuesta correcta tal como se aplica a OP, pero sin ser portátil. (Esto no es una crítica de la respuesta proporcionada, solo una advertencia para los lectores). ;-)
Cbhihe
28

Use el =~operador para hacer comparaciones de expresiones regulares:

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

De esta manera, comparará si $filetiene $testseqen su contenido.

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

Si cambio testseq="Const":

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

Pero tenga cuidado con lo que alimenta $testseq. Si la cadena en él de alguna manera representa una expresión regular (como [0-9]por ejemplo), hay más posibilidades de desencadenar una "coincidencia".

Referencia :


fuente
20
file="JetConst_reco_allconst_4j2t.png"
testseq="gen"

case "$file" in
    *_"$testseq"_*) echo 'True'  ;;
    *)              echo 'False'
esac

Usar case ... esaces una de las formas más sencillas de realizar una coincidencia de patrones de forma portátil. Funciona como una declaración "switch" en otros idiomas ( bash, zshy ksh93también le permite hacer caer a través de varias formas incompatibles). Los patrones utilizados son los patrones estándar de nombres de archivo.

El problema que tiene se debe al hecho de que _es un carácter válido en un nombre de variable. El shell se verá así *_$testseq_*como " *_seguido por el valor de la variable $testseq_y un *". La variable $testseq_no está definida, por lo que se expandirá a una cadena vacía y terminará con *_*, que obviamente coincide con el $filevalor que tiene. Puede esperar obtener Truesiempre que el nombre de archivo $filecontenga al menos un guión bajo.

Para delimitar correctamente el nombre de la variable, el uso "..."alrededor de la expansión: *_"$testseq"_*. Esto usaría el valor de la variable como una cadena. Si desea utilizar el valor de la variable como patrón , utilice *_${testseq}_*en su lugar.

Otra solución rápida es incluir los guiones bajos en el valor de $testseq:

testseq="_gen_"

y luego simplemente usar *"$testseq"*como patrón (para una comparación de cadenas).

Kusalananda
fuente
Por lo tanto, el shell buscará una variable $ testseq_ y no la encontrará y la sustituirá por una cadena vacía.
Viesturs
@Viesturs Ese es el corazón del problema, sí.
Kusalananda
1
Para buscar una subcadena que debe ser *"$testseq"*de caseigual a [[...]](a excepción de zsh a menos que habilite globsubst)
Stéphane Chazelas