string - texto - Cómo verificar si una cadena contiene una subcadena en Bash




separar cadenas bash (14)

Respuesta compatible

Como ya hay muchas respuestas utilizando las funciones específicas de Bash, hay una forma de trabajar bajo shells con características más pobres, como busybox :

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

En la práctica, esto podría 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

Esto se probó bajo bash , dash , ksh y ash (busybox), y el resultado es siempre:

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

En una funcion

Según lo solicitado por @EeroAaltonen, aquí hay una versión de la misma demostración, probada bajo los mismos shells:

myfunc() {
    reqsubstr="$1"
    shift
    string="[email protected]"
    if [ -z "${string##*$reqsubstr*}" ] ;then
        echo "String '$string' contain substring: '$reqsubstr'.";
      else
        echo "String '$string' don't contain substring: '$reqsubstr'." 
    fi
}

Entonces:

$ 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: usted tiene que escapar o doble comillas y / o comillas dobles:

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

Función simple

Esto fue probado bajo busybox , dash y, por supuesto, bash :

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

¡Eso es todo amigos!

Entonces ahora:

$ 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

... O si la cadena enviada podría estar vacía, como señaló @Sjlver, la función se convertiría en:

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

o según lo sugerido por el comentario de Adrian Günter , evitando -o switche:

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

Con cuerdas vacías:

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

https://code.i-harness.com

Tengo una cadena en Bash:

string="My string"

¿Cómo puedo probar si contiene otra cadena?

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

Donde ?? es mi operador desconocido ¿Uso echo y grep ?

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

Eso se ve un poco torpe.


Bash4 + ejemplos. Nota: no usar comillas causará problemas cuando las palabras contengan espacios, etc. Siempre cite en bash IMO.

Aquí hay algunos ejemplos de BASH4 +:

Ejemplo 1, verifique 'sí' en la cadena (no distingue mayúsculas y minúsculas):

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

Ejemplo 2, verifique 'sí' en la cadena (no distingue mayúsculas y minúsculas):

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

Ejemplo 3, verifique 'sí' en la cadena (distingue entre mayúsculas y minúsculas):

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

Ejemplo 4, verifique 'sí' en la cadena (distingue entre mayúsculas y minúsculas):

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

Ejemplo 5, coincidencia exacta (distingue mayúsculas y minúsculas):

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

Ejemplo 6, coincidencia exacta (no distingue mayúsculas y minúsculas):

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

Ejemplo 7, coincidencia exacta:

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

disfrutar.


Como Pablo mencionó en su comparación de desempeño:

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

Esto es compatible con POSIX como la respuesta 'case' $ string 'provista por Marcus, pero es un poco más fácil de leer que la respuesta de la declaración del caso. También tenga en cuenta que esto será mucho más lento que usar una declaración de caso, como lo señaló Paul, no lo use en un bucle.


Debe recordar que los scripts de shell son menos de un lenguaje y más de una colección de comandos. Instintivamente, usted piensa que este "lenguaje" requiere que siga un if con un [ o un [[ . Ambos son solo comandos que devuelven un estado de salida que indica el éxito o el fracaso (como cualquier otro comando). Por esa razón usaría grep , y no el [ comando.

Solo haz:

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

Ahora que está pensando if probando el estado de salida del comando que lo sigue (complete con punto y coma). ¿Por qué no reconsiderar el origen de la cadena que está probando?

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

La opción -q hace que grep no genere nada, ya que solo queremos el código de retorno. <<< hace que el shell expanda la siguiente palabra y la use como entrada para el comando, una versión de una línea del documento << aquí (no estoy seguro si esto es estándar o un bashismo).


Entonces, hay muchas soluciones útiles para la pregunta, pero ¿cuál es la más rápida / usa el menor recurso?

Pruebas repetidas utilizando este marco:

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

Reemplazo de PRUEBA cada vez:

[[ $b =~ $a ]]           2.92user 0.06system 0:02.99elapsed 99%CPU

[ "${b/$a//}" = "$b" ]   3.16user 0.07system 0:03.25elapsed 99%CPU

[[ $b == *$a* ]]         1.85user 0.04system 0:01.90elapsed 99%CPU

case $b in *$a):;;esac   1.80user 0.02system 0:01.83elapsed 99%CPU

doContain $a $b          4.27user 0.11system 0:04.41elapsed 99%CPU

(DoContain estaba en la respuesta de F. Houri)

Y para las risitas:

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

Por lo tanto, la opción de sustitución simple gana de manera predecible ya sea en una prueba extendida o en un caso. El estuche es portátil.

¡Llegar a 100000 greps es predeciblemente doloroso! La vieja regla sobre el uso de utilidades externas sin necesidad es cierta.


Esto también funciona:

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

Y la prueba negativa es:

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

Supongo que este estilo es un poco más clásico, menos dependiente de las características de Bash shell.

El argumento es pura paranoia de POSIX, usado para protegerse contra cadenas de entrada similares a opciones, tales como --abc o -a .

Nota: en un circuito cerrado, este código será mucho más lento que el uso de las funciones internas de Bash shell, ya que uno (o dos) procesos separados se crearán y conectarán a través de tuberías.


La respuesta aceptada es la mejor, pero como hay más de una forma de hacerlo, aquí hay otra solución:

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

${var/search/replace} es $var con la primera instancia de search reemplazada por replace , si se encuentra (no cambia $var ). Si intentas reemplazar foo por nada y la cadena ha cambiado, obviamente se encontró foo .


Me gusta sed

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

Edición, Lógica:

  • Utilice sed para eliminar la instancia de subcadena de cadena

  • Si la cadena nueva difiere de la cadena antigua, existe la subcadena


No estoy seguro de usar una declaración if, pero puede obtener un efecto similar con una declaración de caso:

case "$string" in 
  *foo*)
    # Do stuff
    ;;
esac

Qué tal esto:

text="   <tag>bmnmn</tag>  "
if [[ "$text" =~ "<tag>" ]]; then
   echo "matched"
else
   echo "not matched"
fi

También puede usar la respuesta de Marcus (* comodines) fuera de una declaración de caso, si usa corchetes dobles:

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

Tenga en cuenta que los espacios en la cadena de la aguja deben colocarse entre comillas dobles, y los comodines * deben estar fuera.


Uno es:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'

grep -q es útil para este propósito.

Lo mismo usando awk :

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

Salida:

Extraviado

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

Salida:

Encontró

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


Esta respuesta de desbordamiento de pila fue la única que atrapó el espacio y los caracteres del tablero:

# For null cmd arguments checking   
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found






substring