Cómo procesar cada línea recibida como resultado del comando grep


152

Tengo varias líneas recuperadas de un archivo después de ejecutar el comando grep de la siguiente manera:

var=`grep xyz abc.txt`

Digamos que obtuve 10 líneas que consisten en xyz como resultado.

Ahora necesito procesar cada línea que obtuve como resultado del comando grep. ¿Cómo procedo para esto?


66
Ninguna de las respuestas aquí menciona el poder de grep -oeste tipo de cosas. La -obandera devolverá solo el texto que coincida, con una coincidencia por línea de salida. (No es exhaustivo, por lo que echo aaa |grep 'a*'solo te da "aaa" y omite las tres coincidencias parciales "", "a" y "aa")
Adam Katz

Respuestas:


269

Una de las formas fáciles es no almacenar la salida en una variable, sino iterar directamente sobre ella con un ciclo while / read.

Algo como:

grep xyz abc.txt | while read -r line ; do
    echo "Processing $line"
    # your code goes here
done

Hay variaciones en este esquema dependiendo de exactamente lo que buscas.

Si necesita cambiar las variables dentro del ciclo (y hacer que ese cambio sea visible fuera de él), puede usar la sustitución del proceso como se indica en la respuesta de fedorqui :

while read -r line ; do
    echo "Processing $line"
    # your code goes here
done < <(grep xyz abc.txt)

si no hay línea con xyz?
XYZ_Linux

Entonces no pasa nada, el bucle no se ejecuta.
Mat

13
El problema con este método es que (debido a la tubería) todo dentro del bucle está en una subshell, por lo que establecer variables definidas fuera del bucle durante el bucle no hace que sus valores estén disponibles después del bucle.
David Doria el

3
@David: proporcionó una alternativa para abordar su inquietud. (Fedorqui ya lo había abordado también.)
Mat

Para los comandos cuya última línea de salida no termina con una nueva línea, necesitaría: while read p || [[ -n $p ]]; do ...(tomado de stackoverflow.com/questions/1521462/… )
Ohad Schneider

21

Puede hacer el siguiente while readbucle, que se alimentará del resultado del grepcomando utilizando la llamada sustitución de proceso:

while IFS= read -r result
do
    #whatever with value $result
done < <(grep "xyz" abc.txt)

De esta manera, no tiene que almacenar el resultado en una variable, sino "inyectar" directamente su salida al bucle.


Tenga en cuenta el uso IFS=y de read -racuerdo con las recomendaciones de BashFAQ / 001: ¿Cómo puedo leer un archivo (flujo de datos, variable) línea por línea (y / o campo por campo)? :

La opción -r para leer evita la interpretación de la barra invertida (generalmente se usa como un par de línea nueva de barra invertida, para continuar en varias líneas o para escapar de los delimitadores). Sin esta opción, cualquier barra invertida sin escape en la entrada será descartada. Casi siempre debe usar la opción -r con lectura.

En el escenario anterior, IFS = evita el recorte de los espacios en blanco iniciales y finales. Elimínalo si quieres este efecto.

En cuanto a la sustitución del proceso, se explica en la página de hackers de bash :

La sustitución de procesos es una forma de redireccionamiento donde la entrada o salida de un proceso (alguna secuencia de comandos) aparece como un archivo temporal.


OK, marqué la forversión. Intenté hacer un bucle "${$(grep xyz abc.txt)[@]}"como en stackoverflow.com/a/14588210/1983854 pero no pude. Así que solo dejo la primera versión.
fedorqui 'SO deja de dañar'

1
No puede aplicar la expansión de parámetros a una sustitución de comando (a menos que esté usando zsh, donde ese tipo de anidamiento probablemente funcione).
chepner

Un posible problema con este idioma es que si algo dentro del bucle intenta leer desde la entrada estándar, obtendrá parte del archivo. Para evitar esta posibilidad, me gusta enviar el archivo a través del descriptor de archivo 3 en lugar de stdin. Solo use while IFS= read -r result <&3ydone 3< <(grep ...
Gordon Davisson

8

Sugeriría usar awk en lugar de grep + algo más aquí.

awk '$0~/xyz/{ //your code goes here}' abc.txt


1
¿Cómo haría referencia a la línea completa encontrada //your code goes here?
user857990

2
@ user857990 Toda la línea se representa como $ 0 en AWK.
Julien Grenier

2

Sin ninguna iteración con la opción grep --line-buffered:

your_command | grep --line-buffered "your search"

Ejemplo de la vida real con una salida del comando de depuración del enrutador Symfony PHP Framework, para seleccionar todas las rutas relacionadas con "api":

php bin/console d:r | grep --line-buffered "api"

La única solución que funciona si your_command es de larga duración (como tail -f some.log, en mi caso) ...
Izkata

0

A menudo, el orden del procesamiento no importa. GNU Parallel está hecho para esta situación:

grep xyz abc.txt | parallel echo do stuff to {}

Si el procesamiento es más como:

grep xyz abc.txt | myprogram_reading_from_stdin

y myprogrames lento, entonces puedes ejecutar:

grep xyz abc.txt | parallel --pipe myprogram_reading_from_stdin

0

Iterar sobre los resultados grep con un ciclo while / read. Me gusta:

grep pattern filename.txt | while read -r line ; do
    echo "Matched Line:  $line"
    # your code goes here
done

0

Para aquellos que buscan una línea:

grep xyz abc.txt | while read -r line; do echo "Processing $line"; done
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.