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




shell texto (18)

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.


Answers

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


Qué tal esto:

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

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.


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 .


Coincidencia exacta de la palabra:

string='My long string'
exactSearch='long'

if grep -E -q "\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
  then
    echo "It's there"
  fi

[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"

Si prefiere el enfoque de expresiones regulares:

string='My string';

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

Yo uso esta función (una dependencia no incluida pero obvia). Pasa las pruebas que se muestran a continuación. Si la función devuelve un valor> 0, se encontró la cadena. Podrías devolver 1 o 0 con la misma facilidad.

function str_instr {
   # Return position of ```str``` within ```string```.
   # >>> str_instr "str" "string"
   # str: String to search for.
   # string: String to search.
   typeset str string x
   # Behavior here is not the same in bash vs ksh unless we escape special characters.
   str="$(str_escape_special_characters "${1}")"
   string="${2}"
   x="${string%%$str*}"
   if [[ "${x}" != "${string}" ]]; then
      echo "${#x} + 1" | bc -l
   else
      echo 0
   fi
}

function test_str_instr {
   str_instr "(" "'[email protected] (dev,web)'" | assert_eq 11
   str_instr ")" "'[email protected] (dev,web)'" | assert_eq 19
   str_instr "[" "'[email protected] [dev,web]'" | assert_eq 11
   str_instr "]" "'[email protected] [dev,web]'" | assert_eq 19
   str_instr "a" "abc" | assert_eq 1
   str_instr "z" "abc" | assert_eq 0
   str_instr "Eggs" "Green Eggs And Ham" | assert_eq 7
   str_instr "a" "" | assert_eq 0
   str_instr "" "" | assert_eq 0
   str_instr " " "Green Eggs" | assert_eq 6
   str_instr " " " Green "  | assert_eq 1
}

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

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.


Uno es:

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

Intente oobash es una biblioteca de cadenas de estilo OO para bash 4. Tiene soporte para diéresis alemanas. Está escrito en bash. Muchas funciones están disponibles: -base64Decode , -base64Encode , -capitalize , -center , -charAt , -concat , -contains , -count , -endsWith , -equals , -equalsIgnoreCase , -reverse , -hashCode , -indexOf , -isAlnum -isAlpha , -isAscii , -isDigit , -isEmpty , -isHexDigit -isLowerCase , -isSpace , -isPrintable , -isUpperCase , -isVisible , -lastIndexOf , -matches , -replaceAll -- -replaceFirst -startsWith -substring -startsWith -substring -startsWith -substring -startsWith -substring -startsWith -substring , -swapCase , -toLowerCase , -toString , -toUpperCase , -trim , y -zfill .

Mira el ejemplo que contiene:

[Desktop]$ String a testXccc                                                  
[Desktop]$ a.contains tX                   
true                                                           
[Desktop]$ a.contains XtX      
false      

oobash está disponible en Sourceforge.net .


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.


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.


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


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

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


Contra lo que parece ser una práctica común entre otros programadores, prefiero String sobre string , solo para resaltar el hecho de que String es un tipo de referencia, como mencionó Jon Skeet.





string bash substring