Cómo verificar si una cadena contiene una subcadena en Bash

2576

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

¿Dónde ??está mi operador desconocido? ¿Utilizo echo y grep?

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

Eso se ve un poco torpe.

davidsheldon
fuente
44
Hola, si las cadenas vacías son falsas, ¿por qué lo consideras torpe? Fue la única forma que funcionó para mí, a pesar de las soluciones propuestas.
ericson.cepeda
1
Puede usar el exprcomando aquí
cli__
44
Aquí hay uno para los shells posix: stackoverflow.com/questions/2829613/…
sehe

Respuestas:

3658

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 afuera. También tenga en cuenta que se utiliza un operador de comparación simple (es decir ==), no el operador de expresiones regulares =~.

Adam Bellaire
fuente
127
También tenga en cuenta que puede revertir la comparación simplemente cambiando a! = En la prueba. ¡Gracias por la respuesta!
Quinn Taylor el
63
@ Jonik: Es posible que te pierdas el shebang o que lo tengas como #!/bin/sh. Intenta en su #!/bin/bashlugar.
Pausado hasta nuevo aviso.
10
Deje un espacio entre los corchetes y el contenido.
Paul Price
17
No necesita citar variables dentro de [[]]. Esto funcionará igual de bien: [[$ string == $ needle ]] && echo found
Orwellophile
13
@Orwellophile ¡Cuidado! Solo puede omitir las comillas dobles en el primer argumento de [[. Ver ideone.com/ZSy1gZ
nyuszika7h
613

Si prefiere el enfoque regex:

string='My string';

if [[ $string =~ "My" ]]
then
   echo "It's there!"
fi
Matt Tardiff
fuente
2
Tuve que reemplazar una expresión regular egrep en un script bash, ¡esto funcionó perfectamente!
blast_hardcheese
114
El =~operador ya busca en toda la cadena una coincidencia; los .*'s aquí son extraños. Además, las citas son generalmente preferibles a las barras invertidas:[[ $string =~ "My s" ]]
bukzor
16
@bukzor Quotes dejó de funcionar aquí a partir de Bash 3.2+: tiswww.case.edu/php/chet/bash/FAQ E14) . Probablemente sea mejor asignar a una variable (usando comillas), luego comparar. Así:re="My s"; if [[ $string =~ $re ]]
seanf
36
Probar si NO contiene una cadena: if [[ ! "abc" =~ "d" ]]es verdadero.
KrisWebDev
1
Tenga en cuenta que el orden en que ocurre la prueba es importante. La salida de la siguiente línea de código será hacia adelante 2.number=2; if [[ "1, 2, 4, 5" = *${number}* ]]; then echo forward $number; fi; if [[ *${number}* = "1, 2, 4, 5" ]]; then echo backwards $number; fi;
Douwe van der Leest
358

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
Marcus Griep
fuente
76
Esta es probablemente la mejor solución, ya que es portátil para los shells posix. (aka no bashisms)
technosaurus
25
@technosaurus Me resulta bastante extraño criticar el "bashismo" en una pregunta que solo tiene etiqueta bash :)
PP
39
@PP No es tanto una crítica como la preferencia de una solución más universal sobre una más limitada. Tenga en cuenta que, años más tarde, las personas (como yo) se detendrán para buscar esta respuesta y pueden estar contentos de encontrar una que sea útil en un ámbito más amplio que la pregunta original. Como dicen en el mundo de código abierto: "¡la elección es buena!"
Carl Smotricz
2
@technosaurus, FWIW [[ $string == *foo* ]]también funciona en algunas versiones sh compatibles con POSIX (por ejemplo, /usr/xpg4/bin/shen Solaris 10) y ksh (> = 88)
maxschlepzig
3
La ceniza Busybox no maneja asteriscos en [[... ¡el interruptor de la caja funcionó!
Ray Foss
233

stringContain variantes (compatibles o independientes de mayúsculas y minúsculas)

Como estas respuestas de desbordamiento de pila se refieren principalmente a Bash , he publicado una función Bash independiente del caso en la parte inferior de esta publicación ...

De todos modos, ahí está mi

Respuesta compatible

Como ya hay muchas respuestas usando las características específicas de Bash, hay una manera 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ó en Bash, Dash , KornShell ( 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 función

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="$@"
    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: 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 se probó en BusyBox, Dash y, por supuesto, Bash:

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

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 pudiera estar vacía, como lo señaló @Sjlver, la función sería:

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

o como lo sugiere el comentario de Adrian Günter , evitando -ointerruptores:

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

Función final (simple):

E invirtiendo las pruebas para que sean potencialmente más rápidas:

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

Con cadenas vacías:

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

Caso independiente (¡solo Bash!)

Para probar cadenas sin cuidado de mayúsculas y minúsculas, simplemente convierta cada cadena a minúsculas:

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

Cheque:

stringContain 'o "M3' 'echo "my string"' && echo yes || echo no
no
stringContain 'o "My' 'echo "my string"' && echo yes || echo no
yes
if stringContain '' ''; then echo yes; else echo no; fi
yes
if stringContain 'o "M' ''; then echo yes; else echo no; fi
no
F. Hauri
fuente
1
Esto sería aún mejor, si puedes encontrar alguna manera de poner eso en una función.
Eero Aaltonen
2
@EeroAaltonen ¿Cómo encuentra mi función (nueva agregada)?
F. Hauri
2
¡Lo sé! encontrar . -nombre "*" | xargs grep "myfunc" 2> / dev / null
eggmatters
66
Esto es maravilloso porque es muy compatible. Sin embargo, un error: no funciona si la cadena del pajar está vacía. La versión correcta sería string_contains() { [ -z "${2##*$1*}" ] && [ -n "$2" -o -z "$1" ]; } Un pensamiento final: ¿la cadena vacía contiene la cadena vacía? La versión anterior dice sí (debido a la -o -z "$1"parte).
Sjlver
3
+1. ¡Muy bien! Para mí, cambié el orden stringContain () {[-z "$ {1 ## * $ 2 *}"] && [-z "$ 2" -o -n "$ 1"]; }; "Buscar dónde" "Encontrar qué". Trabaja en busybox. La respuesta aceptada arriba no funciona en busybox.
user3439968
149

Debe recordar que las secuencias de comandos de shell son menos un lenguaje y más una colección de comandos. Instintivamente piensas que este "lenguaje" requiere que sigas a ifcon a [o a [[. Ambos son solo comandos que devuelven un estado de salida que indica éxito o 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 ifen probar el estado de salida del comando que lo sigue (completo con punto y coma), ¿por qué no reconsiderar la fuente 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 -qopción hace que grep no muestre 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 de si esto es estándar o un Bashism).

Mark Baker
fuente
77
se llaman aquí cadenas (3.6.7) Creo que es bashism
alex.pilon
10
también se puede usar la sustitución de procesos if grep -q foo <(echo somefoothing); then
larsr
Tenga en cuenta que no echoes portátil, si está pasando una variable, use printf '%s' "$stringen su lugar.
nyuszika7h
55
El costo de esto es muy costoso: hacer grep -q foo <<<"$mystring"1 tenedor implícito y es bashism e implicaecho $mystring | grep -q foo 2 tenedores (uno para la tubería y el segundo para correr /path/to/grep)
F. Hauri
1
@BrunoBronosky echosin banderas aún podría tener problemas de portabilidad inesperados si la cadena de argumentos contiene secuencias de barra invertida. echo "nope\c"se espera que en algunas plataformas funcione como echo -e "nope"en otras. printf '%s' "nope"vsprintf '%s\n' 'nope\c'
tripleee
92

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 $varcon la primera instancia de searchreemplazado por replace, si se encuentra (no cambia $var). Si intenta reemplazar foopor nada, y la cadena ha cambiado, entonces obviamente foose encontró.

efímero
fuente
55
la solución de ephemient anterior:> `if [" $ string "! =" $ {string / foo /} "]; entonces echo "¡Está ahí!" fi` es útil cuando se utiliza la ceniza de shell de BusyBox . La solución aceptada no funciona con BusyBox porque algunas expresiones regulares de bash no están implementadas.
TPoschel
1
La desigualdad de la diferencia. ¡Pensamiento bastante extraño! Me encanta
nitinr708
1
sin embargo
venimus
Yo mismo escribí esta misma solución (porque mi intérprete no tomaría las mejores respuestas) y luego busqué una mejor, ¡pero encontré esto!
BuvinJ
56

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

Pruebas repetidas usando este marco:

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

Reemplazar TEST cada vez:

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

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

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

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

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

(doContain estaba en la respuesta de F. Houri)

Y para las risas:

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

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

¡Contar con 100000 greps es previsiblemente doloroso! La antigua regla sobre el uso de utilidades externas sin necesidad es cierta.

Paul Hedderly
fuente
44
Punto de referencia ordenado. Me convenció de usar [[ $b == *$a* ]].
Físico loco
2
Si estoy leyendo esto correctamente, casegana con el menor consumo de tiempo total. Sin $b in *$aembargo, te falta un asterisco después . Obtengo resultados ligeramente más rápidos para [[ $b == *$a* ]]que casecon el error corregido, pero podría depender de otros factores también, por supuesto.
tripleee
1
ideone.com/5roEVt tiene mi experimento con algunos errores adicionales corregidos y prueba para un escenario diferente (donde la cadena no está realmente presente en la cadena más larga). Los resultados son en gran medida similares; [[ $b == *$a* ]]es rápido y casees casi tan rápido (y agradablemente compatible con POSIX).
tripleee
28

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 del shell Bash.

El --argumento es pura paranoia POSIX, utilizada para proteger contra cadenas de entrada similares a las opciones, como --abco-a .

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

kevinarpe
fuente
55
... pero el OP no dice qué versión de bash; por ejemplo, los bash más antiguos (como los que suele tener Solaris) pueden no incluir estas nuevas funciones de bash. (Me he encontrado con este problema exacto (la coincidencia de patrones de bash no está implementada) en solaris con bash 2.0)
michael
2
echono es portátil, deberías usarlo en su printf '%s' "$haystacklugar.
nyuszika7h
2
No, solo evite echopor completo cualquier cosa que no sea texto literal sin escapes que no comience con a -. Puede funcionar para usted, pero no es portátil. Incluso bash echose comportará de manera diferente dependiendo de si la xpg_echoopción está configurada. PD: Olvidé cerrar la comilla doble en mi comentario anterior.
nyuszika7h
1
@kevinarpe No estoy seguro, --no aparece en la especificación POSIX paraprintf , pero debe usar de printf '%s' "$anything"todos modos, para evitar problemas si $anythingcontiene un %carácter.
nyuszika7h
1
@kevinarpe Basado en eso, probablemente lo sea.
nyuszika7h
21

Bash 4+ ejemplos. Nota: no usar comillas causará problemas cuando las palabras contengan espacios, etc. Comillas siempre en Bash, IMO.

Aquí hay algunos ejemplos de Bash 4+:

Ejemplo 1, verifique 'sí' en la cadena (sin distinción entre mayúsculas y minúsculas):

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

Ejemplo 2, verifique 'sí' en la cadena (sin distinción entre 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 (mayúsculas y minúsculas):

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

Ejemplo 6, coincidencia exacta (sin distinción entre mayúsculas y minúsculas):

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

Ejemplo 7, coincidencia exacta:

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

Ejemplo 8, coincidencia con comodines .ext (sin distinción entre mayúsculas y minúsculas):

     if echo "$a" | egrep -iq "\.(mp[3-4]|txt|css|jpg|png)" ; then

Disfrutar.

Mike Q
fuente
17

Qué tal esto:

text="   <tag>bmnmn</tag>  "
if [[ "$text" =~ "<tag>" ]]; then
   echo "matched"
else
   echo "not matched"
fi
bn.
fuente
2
= ~ es para la coincidencia de expresiones regulares, por lo tanto, demasiado potente para el propósito del OP.
16

Como Paul mencionó en su comparación de rendimiento:

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 el 'case "$ string" en' la respuesta proporcionada por Marcus , pero es un poco más fácil de leer que la respuesta de la declaración de caso. También tenga en cuenta que esto será mucho más lento que usar una declaración de caso. Como señaló Paul, no lo use en un bucle.

Samuel
fuente
11

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

# For null cmd arguments checking   
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found
Yordan Georgiev
fuente
Es una respuesta a esta misma pregunta.
Peter Mortensen
9
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"
Jahid
fuente
Agregaré que la echo "Couldn't finddeclaración al final es un buen truco para devolver 0 estados de salida para estos comandos coincidentes.
nicodjimenez
@nicodjimenez ya no puedes apuntar al estado de salida con esta solución. El estado de salida es absorbido por los mensajes de estado ...
Jahid
1
Eso es exactamente lo que quise decir ... Si no lo tiene || echo "Couldn't find", devolverá un estado de salida de error si no hay coincidencia, lo que puede que no desee si está ejecutando una canalización de CI, por ejemplo, donde desea que regresen todos los comandos estados de salida sin error
nicodjimenez
9

Uno es:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'
chemila
fuente
2
expres una de esas utilidades de navaja suiza que generalmente puede hacer lo que sea que necesites hacer, una vez que descubres cómo hacerlo, pero una vez implementado, nunca puedes recordar por qué o cómo está haciendo lo que está haciendo, así que nunca lo toque de nuevo y espere que nunca deje de hacer lo que está haciendo.
michael
@AloisMahdal Nunca voté en contra, solo estoy postulando sobre por qué se dieron votos negativos. Un comentario de advertencia. Yo uso expr, en raras ocasiones, cuando la portabilidad impide el uso de bash (por ejemplo, comportamiento inconsistente en versiones anteriores), tr (inconsistente en todas partes) o sed (a veces demasiado lento). Pero por experiencia personal, cada vez que exprreleo estos ismos, tengo que volver a la página del manual. Por lo tanto, me acaba de comentar que cada uso de exprser comentado ...
Michael
1
Hubo un tiempo en que todo lo que tenía era el shell Bourne original. Carecía de algunas características comúnmente requeridas, por lo que herramientas como expry testse implementaron para realizarlas. En la actualidad, generalmente hay mejores herramientas, muchas de ellas integradas en cualquier shell moderno. Supongo testque todavía está ahí, pero parece que no falta nadie expr.
tripleee
6

Me gusta sed

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

Editar, Lógica:

  • Use sed para eliminar la instancia de la subcadena de la cadena

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

paseo
fuente
2
Por favor agregue alguna explicación. Impartir la lógica subyacente es más importante que acaba de dar el código, ya que ayuda a la OP y otros lectores de solucionar este problema y cuestiones similares a sí mismos
Zulan
5

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

nyuszika7h
fuente
3
echono es portátil, deberías usarlo en su printf '%s' "$string"lugar. Estoy editando la respuesta porque el usuario ya no parece existir.
nyuszika7h
¿De qué manera echono es portátil, @ nyuszika7h?
starbeamrainbowlabs
5

Descubrí que necesitaba esta funcionalidad con bastante frecuencia, por lo que estoy usando una función de shell casera en mi .bashrcestilo que me permite reutilizarla tantas veces como sea necesario, con un nombre fácil de recordar:

function stringinstring()
{
    case "$2" in
       *"$1"*)
          return 0
       ;;
    esac
    return 1
}

Para probar si $string1(digamos, abc ) está contenido en $string2(digamos, 123abcABC ) solo necesito ejecutar stringinstring "$string1" "$string2"y verificar el valor de retorno, por ejemplo

stringinstring "$str1" "$str2"  &&  echo YES  ||  echo NO
Kurt Pfeifle
fuente
[["$ str" == $ substr ]] && echo YES || echo NO
elyase
Estoy bastante seguro de que el xtruco solo es necesario para conchas muy antiguas.
nyuszika7h
5

My .bash_profile archivo y cómo usé grep:

Si la variable de entorno PATH incluye mis dos bindirectorios, no los agregue,

# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

U=~/.local.bin:~/bin

if ! echo "$PATH" | grep -q "home"; then
    export PATH=$PATH:${U}
fi
Leslie Satenstein
fuente
1
¿Es esta una respuesta?
codeforester
voto a favor ¿Por qué molestarse en aprender cómo lo hace Bash cuando grep, mucho más poderoso, es más que probable que esté disponible? también se extienden un poco más allá por coincidencia contra una lista de patrones: grep -q -E 'pattern1|...|patternN'.
Mohamed Bana
4

Extensión de la pregunta respondida aquí ¿Cómo saber si una cadena contiene otra cadena en POSIX sh? :

Esta solución funciona con caracteres especiales:

# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
    string="$1"
    substring="$2"

    if echo "$string" | $(type -p ggrep grep | head -1) -F -- "$substring" >/dev/null; then
        return 0    # $substring is in $string
    else
        return 1    # $substring is not in $string
    fi
}

contains "abcd" "e" || echo "abcd does not contain e"
contains "abcd" "ab" && echo "abcd contains ab"
contains "abcd" "bc" && echo "abcd contains bc"
contains "abcd" "cd" && echo "abcd contains cd"
contains "abcd" "abcd" && echo "abcd contains abcd"
contains "" "" && echo "empty string contains empty string"
contains "a" "" && echo "a contains empty string"
contains "" "a" || echo "empty string does not contain a"
contains "abcd efgh" "cd ef" && echo "abcd efgh contains cd ef"
contains "abcd efgh" " " && echo "abcd efgh contains a space"

contains "abcd [efg] hij" "[efg]" && echo "abcd [efg] hij contains [efg]"
contains "abcd [efg] hij" "[effg]" || echo "abcd [efg] hij does not contain [effg]"

contains "abcd *efg* hij" "*efg*" && echo "abcd *efg* hij contains *efg*"
contains "abcd *efg* hij" "d *efg* h" && echo "abcd *efg* hij contains d *efg* h"
contains "abcd *efg* hij" "*effg*" || echo "abcd *efg* hij does not contain *effg*"
Alex Skrypnyk
fuente
¡La prueba contains "-n" "n"no funciona aquí, porque echo -nse tragará -ncomo una opción! Una solución popular para eso es usar printf "%s\n" "$string"en su lugar.
joeytwiddle
cadena perfectamente resuelta contenía espacios
dengApro
4

Desde el POSIX pregunta / BusyBox está cerrada sin proporcionar la respuesta correcta (en mi humilde opinión), publicaré una respuesta aquí.

La respuesta más corta posible es:

[ ${_string_##*$_substring_*} ] || echo Substring found!

o

[ "${_string_##*$_substring_*}" ] || echo 'Substring found!'

Tenga en cuenta que el doble hash es obligatorio con algunos shells ( ash). Lo anterior evaluará [ stringvalue ]cuando no se encuentre la subcadena. No devuelve ningún error. Cuando se encuentra la subcadena, el resultado está vacío y se evalúa [ ]. Esto arrojará el código de error 1 ya que la cadena está completamente sustituida (debido a* ).

La sintaxis más corta más común:

[ -z "${_string_##*$_substring_*}" ] && echo 'Substring found!'

o

[ -n "${_string_##*$_substring_*}" ] || echo 'Substring found!'

Otro:

[ "${_string_##$_substring_}" != "$_string_" ] && echo 'Substring found!'

o

[ "${_string_##$_substring_}" = "$_string_" ] || echo 'Substring found!'

Tenga en cuenta el signo igual único !

Quinto axioma
fuente
3

Concordancia exacta de palabras:

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

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

Prueba oobash.

Es una biblioteca de cadenas de estilo OO para Bash 4. Tiene soporte para diéresis alemanas. Está escrito en Bash.

Muchas de las 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, -length, -matches, -replaceAll, -replaceFirst, -startsWith, -substring, -swapCase, -toLowerCase, -toString, -toUpperCase, -trim, y -zfill.

Mira el ejemplo contiene :

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

oobash está disponible en Sourceforge.net .

andreas
fuente
2

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ía simplemente devolver 1 o 0 en su lugar.

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 "(" "'foo@host (dev,web)'" | assert_eq 11
   str_instr ")" "'foo@host (dev,web)'" | assert_eq 19
   str_instr "[" "'foo@host [dev,web]'" | assert_eq 11
   str_instr "]" "'foo@host [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
}
Ethan Post
fuente
¡El suspenso! ¿Cuál es la dependencia?
Peter Mortensen
La función "str_escape_special_characters". Está en el archivo GitHub arcshell_str.sh. arcshell.io te llevará allí.
Ethan Post
0
msg="message"

function check {
    echo $msg | egrep [abc] 1> /dev/null

    if [ $? -ne 1 ];
    then 
        echo "found" 
    else 
        echo "not found" 
    fi
}

check

Esto encontrará cualquier ocurrencia de a o b o c

BobMonk
fuente
0

El ejemplo genérico de pajar de agujas está siguiendo con variables

#!/bin/bash

needle="a_needle"
haystack="a_needle another_needle a_third_needle"
if [[ $haystack == *"$needle"* ]]; then
    echo "needle found"
else
    echo "needle NOT found"
fi
Pipo
fuente