texto subcadena separar script reemplazar manipulacion manejo extraer cortar comparar caracter cadenas cadena buscar string bash substring

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



manipulacion de cadenas de texto bash (21)

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.


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="$@" 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


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.


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


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


Descubrí que necesitaba esta funcionalidad con bastante frecuencia, así que estoy usando una función de shell hecha en casa en mi .bashrc como esta, que me permite reutilizarla con la frecuencia que necesito, con un nombre fácil de recordar:

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

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

stringinstring "$str1" "$str2" && echo YES || echo NO


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.


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 .


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


Mi .bash_profile y cómo utilicé grep si la RUTA incluía mis direcciones de 2 contenedores, 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


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


Si prefiere el enfoque de expresiones regulares:

string=''My string''; if [[ $string =~ .*My.* ]] then echo "It''s there!" 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''


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 "(" "''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 }


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


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