Encuentra una cadena mientras conoces parte de ella y devuelve la cadena

9

Tengo una cuerda, por ejemplo

"Icecream123 AirplaneBCD CompanyTL1 ComputerYU1"

Digamos que sé que mi cadena contendrá con seguridad la subcadena IceCream, pero no sé qué le sigue.

Puede ser 123 como en mi ejemplo o puede ser algo diferente.

Si bien puedo usar grep para detectar si la subcadena "Icecream" existe en mi cadena con el siguiente comando

echo $string | grep -oF 'Icecream';

Que imprimirá

Icecream

Quiero con un comando que imprima toda la subcadena, que en mi ejemplo es

Icecream123

Por supuesto, lo que sigue a Icecream es aleatorio y no se conoce de antemano, así que no puedo hacer

$SUBSTRING=$(echo $string | grep -oF 'Icecream')
$SUBSTRINGTRAIL=123
echo $SUBSTRING$SUBSTRINGTRAIL
Sonamor
fuente
¿Es la subcadena fija / estática, siempre "Icecream", o es variable?
Jeff Schaller
¿un espacio indicará el final del sufijo deseado?
Jeff Schaller
@JeffSchaller Lamentablemente, no lo sé. Realmente estoy obteniendo una salida multilínea de otro comando, que almaceno en una variable, esta variable es mi $ string, cuando se repite, muestra la salida multilínea como una línea de señal con un espacio entre ellos. Realmente no sé si es un espacio o un personaje especial como LF. Pensé que es el espacio.
Sonamor
Quiero decir, por ejemplo, Icecream123 AirplaneBCDquieres parar en 123. ¿Es porque hay un espacio después de los 3, o algo más?
Jeff Schaller
1
Si no está seguro de cuáles son sus datos, es difícil escribir una solución adecuada. Todas las respuestas hasta ahora suponen que sus datos están en una línea, como lo ha mostrado. Estaba tratando de averiguar cuál era su delimitador, dónde debería detenerse la parte "final".
Jeff Schaller

Respuestas:

15

Si grepadmite expresiones regulares compatibles con Perl, puede hacer coincidir de forma no codiciosa hasta el siguiente límite de palabra:

echo "$string" | grep -oP 'Icecream.*?\b'

De lo contrario, haga coincidir la secuencia más larga de caracteres no en blanco:

echo "$string" | grep -o 'Icecream[^[:blank:]]*'

O mantenga todo en el shell y elimine la secuencia de caracteres más larga que comienza con un espacio:

echo "${string%% *}"
conductor de acero
fuente
2
Para PCRE, lo usaría 'Icecream\S+'para algunos caracteres no en blanco.
Glenn Jackman
Gracias por sus comentarios, lamentablemente parece que mi versión de grep no es compatible con perl regex. ¿Podría agregar más detalles sobre su tercera opción? No estoy muy seguro de cómo implementarlo.
Sonamor
Después de algunas pruebas más, parece que usando echo "$ string" | grep -oP 'Icecream. *? \ b' o 'Icecream \ S +' hace el trabajo. Gracias
Sonamor
¡Es realmente confuso que, aunque su variable $ string es una cadena, todavía tiene que ponerla entre comillas dobles!
Sonamor
@Sonamor en este caso la cita no es estrictamente necesaria; Sin embargo, hay tantos casos en los que es un buen hábito entrar. Ver, por ejemplo, ¿ cuándo es necesaria una doble cita?
steeldriver
7

Usando un grepque sabe sobre -o:

$ printf '%s\n' "$string" | grep -o '\<Icecream[^[:blank:]]*'
Icecream123

El patrón \<Icecream[^[:blank:]]*coincide con la cadena Icecream(donde Iestá precedido por un carácter que no es de palabra, o el comienzo de la línea) seguido de cero o más espacios en blanco (no espacios o tabulaciones).


Utilizando awk:

$ printf '%s\n' "$string" | awk -v RS=' ' '/^Icecream/'       
Icecream123

El awkprograma divide la cadena en registros separados por espacios y prueba cada uno. Imprimirá los que comienzan con la cadena Icecream.

Usando mawko GNU awk, también puede usar

printf '%s\n' "$string" | awk -v RS='[[:blank:]]' '/^Icecream/'

ya que se RSinterpretan como una expresión regular si contiene más de un carácter.


Con sed, de manera similar a como con grep:

$ printf '%s\n' "$string" | sed 's/.*\(\<Icecream[^[:blank:]]*\).*/\1/'
Icecream123

Utilizando /bin/sh:

set -- Icecream123 AirplaneBCD CompanyTL1 ComputerYU1
for string; do
    case $string in
        Icecream*)
            printf '%s\n' "$string"
            break
    esac
done

Perl (con un poco de ayuda de tr):

$ printf '%s\n' "$string" | tr ' ' '\n' | perl -ne '/Icecream\S*/ && print'
Icecream123

o solo

$ printf '%s\n' "$string" | perl -ne '/(Icecream\S*)/ && print $1, "\n"'
Icecream123
Kusalananda
fuente
O, divídalo en líneas y combine la clave:echo "$string" | grep -o '\S\+' | grep "Icecream"
Isaac
7

Desde que etiquetaste bash:

[[ $string =~ (Icecream[^ ]*) ]] && result=${BASH_REMATCH[1]}

Más generalmente, para un término de búsqueda en $search:

[[ $string =~ ($search[^ ]*) ]] && result=${BASH_REMATCH[1]}

... o con expansión de parámetros:

# remove any leading text up to -and through- the search text:
x=${string##*$search}

# remove any trailing space onwards
result=$search${x%% *}
Jeff Schaller
fuente
2

Por ejemplo, si usa GNU grep:

$ echo "Icecream123 AirplaneBCD CompanyTL1 ComputerYU1" | grep -oP '\bIcecream.*?(\s|$)' --color

Lo usa PCRE.

Arkadiusz Drabczyk
fuente
1

Quizás sea un poco más simple, especialmente porque dice que su versión de grep no es compatible con perl regex:

$ echo $string | tr ' ' '\n' | grep 'Icecream' Icecream123

El trdivide la cadena en las líneas mediante la sustitución de todos los espacios con nuevas líneas. Entonces puedes usar grepfácilmente.

También puede escribir lo siguiente para obtener solo lo que sigue a la palabra que está buscando:

$ echo $string | tr ' ' '\n' | sed -n 's/Icecream//p' 123

Ley29
fuente