Prueba si una cadena contiene una subcadena

Tengo el código

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

Pruebo si file contiene «gen». El resultado es «Falso». ¡Genial!

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? ¿Cómo solucionar el problema?

Comentarios

Respuesta

Necesita interpolar el $testseq variable con una de las siguientes formas:

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

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

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

Comentarios

  • Respuesta correcta según se aplica a OP, pero sin ser portátil . (Esta no es una crítica de la respuesta proporcionada, solo una advertencia para los lectores). 😉

Responder

Utilice la =~ operat o 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 $file tiene $testseq en 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 representa de alguna manera una expresión regular (como [0-9] por ejemplo), hay una mayor probabilidad de activar una «coincidencia».

Referencia :

Comentarios

  • Parece que esta respuesta es para " bash " solamente

Responder

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

Usar case ... esac es una de las formas más sencillas de realizar una coincidencia de patrones de forma portátil. Funciona como una declaración de «cambio» en otros idiomas (bash, zsh y ksh93 también le permite hacer fall-through de varias formas incompatibles). Los patrones utilizados son los patrones globales de nombres de archivo estándar.

El problema que tiene se debe al hecho de que _ es un carácter válido en un nombre de variable. Por tanto, el shell verá *_$testseq_* como «*_ seguido del 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 $file valor que tiene. Puede esperar obtener True siempre que el nombre de archivo en $file contenga al menos un guión bajo.

Para correctamente delimite el nombre de la variable, use "..." 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 un patrón , utilice *_${testseq}_* en su lugar.

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

testseq="_gen_" 

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

Comentarios

  • Entonces, el shell buscará una variable $ testseq_ y no encontrará y sustitúyalo por una cadena vacía.
  • @Viesturs Eso ' s es el meollo del problema, sí.
  • Para un búsqueda de subcadenas debe ser *"$testseq"* para case como para [[...]] (excepto para zsh a menos enable globsubst)
  • ¿Más simple que [ "${str##*substr*}" ] || echo True?
  • @Isaac En términos de lectura y comprensión de ' está sucediendo, sí. También es ' fácil extender una prueba con más casos de prueba sin obtener un " if-then-elif-then-elif " espaguetis. Aunque prueba una sola cadena de la forma en que lo muestra (si una cadena desaparece en una sustitución) es más corta.

Respuesta

Para la forma portátil de probar si una cadena contiene una subcadena, use:

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

O "${file##*"$testseq"*}" para evitar la interpretación de caracteres globales en testseq.

Comentarios

  • Usted ' d necesita algo como [" $ {file ## * $ testseq *} "! = " $ file " ] porque en el guión que es Eliminar el patrón de prefijo más grande.
  • No, @NoelGrandin no hay cambios en la mayoría de los shells (incluido el guión), el Patrón de prefijo más grande será la cadena completa si el valor del subpatrón variable ($testseq) está contenido dentro del valor $file. Prueba: dash -c 'file="JetConst_reco_allconst_4j2t.png"; testseq="reco"; echo "=${file##*"$testseq"*}="' para confirmar que el guión eliminará toda la cadena.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *