Combina múltiples comandos de Unix en una salida


9

Necesito buscar en nuestros registros de correo una dirección de correo electrónico específica. Mantenemos un archivo actual llamado maillog , así como una semana de archivos .bz2 en la misma carpeta. Actualmente, estoy ejecutando los siguientes comandos para buscar el archivo:

grep person@domain.com maillog
bzgrep person@domain.com *.bz2

¿Hay alguna forma de combinar los comandos grepy bzgrepen una sola salida? De esa manera, podría canalizar los resultados combinados a un solo correo electrónico o un solo archivo.

Respuestas:


24

Otra forma es

{ grep ...; bzgrep ...;} >file

&&tiene la dificultad de que bzgrepno se ejecute si grepfalla.

Observe el espacio obligatorio después de la llave de apertura y el punto y coma después del último comando. Alternativamente, puede usar la sintaxis de subshell (paréntesis en lugar de llaves), que no es tan exigente:

(grep ...; bzgrep ...) >file

+1 para el mejor enfoque de shell de propósito general para este problema. La agrupación de shell es una característica generalmente infrautilizada.
Phil Hollenback

2
¿No quieres decir en ()lugar de {}?
Ehtesh Choudhury

En arch linux esto funcionó ()pero no {}, de cualquier manera +1 ya que esto es lo que necesitaba.
Chris Magnuson

11

Por defecto, bzgrep se convierte automáticamente en grep normal si un archivo no está comprimido mediante bzip. Por lo tanto, lo siguiente debería ser suficiente:

bzgrep person@domain.com maillog *bz2 | mail -s "logs yay" someuser@blah

oh, por supuesto, aquí también está mi solución paralela obligatoria de GNU :

parallel -m bzgrep person@domain.com ::: maillog* *bz2 | mail -s "logs yay" someuser@blah

que podría ser mucho más rápido si está revisando muchos archivos.


2

Aquí hay otra forma de hacerlo (suponiendo que esté ejecutando bash, que probablemente lo sea):

cat <(bzgrep ...) <(grep ...)

Aquí bash está alimentando de manera transparente la salida de los comandos bzgrep y grep en cat como si fueran archivos (y de alguna manera están debajo del capó, los detalles en la url en la parte inferior).

En su caso particular, recomendaría la solución de Phil, pero lo anterior es un buen truco para guardar en su bolso.

Si está interesado, puede leer más aquí: http://www.tldp.org/LDP/abs/html/process-sub.html


Ah sí, la respuesta canónica para '¿cómo difieren la salida de dos procesos'? Un buen truco para saber.
Phil Hollenback

1

En el momento de escribir esto, la sintaxis de la respuesta aceptada era incorrecta para la mayoría, si no para todos, los shells derivados de Bourne, incluidos bash. Sugerí una edición en la parte superior y acepté la respuesta para corregirlo, pero también me incliné a agregar toda esta otra información, y esto habría sido más una reescritura en lugar de una edición.

Puede usar comandos compuestos:

{ grep ...; bzgrep ...; } >file

..o subcapas (tenga en cuenta los paréntesis en lugar de llaves):

(grep ...; bzgrep ...) >file

..para agrupar los comandos. La forma de subshell tiene una sintaxis más agradable (más indulgente con la falta de espacios en blanco y le permite omitir el último punto y coma), pero bifurca un nuevo proceso o "finge" al ejecutar los comandos en un entorno limpio. Ambos tienen ventajas dependiendo de lo que quieras hacer, lo que no importa aquí, pero vale la pena buscarlo si quieres más habilidad con el shell.

Nota: También puedes usar la canalización con estos trucos, por lo que puedes hacer algo como esto:

{ grep ...; bzgrep ...; } | less

PS si no se preocupan por el orden de los partidos en su salida combinada, se podría utilizar una sola &entre los dos comandos, así: { grep ... & bzgrep ...; }. Luego, los dos comandos se ejecutan simultáneamente: grepse inicia y el shell lo pone en segundo plano, luego el shell ejecutará el bzgrep. (Pero hay una pequeña advertencia con eso, con la explicación que involucra la redirección de archivos y el almacenamiento en búfer de la secuencia de archivos que puede causar que una porción muy pequeña de las líneas en el archivo de salida se divida / destruya: si vería esto dependería de cómo grep, bzgrep, y las libc stdio.hfunciones están implementadas. En la mayoría de las implementaciones, creo que canalizar el comando antes de redirigir a un archivo evitará el problema, por lo que podría hacer { foo & bar; } | cat - >fileuna solución alternativa).


0

Puede vincular los comandos con &&, lo que le permitirá ejecutar cada comando.

también puede agregar >> textfile.txt al final de cada comando y hacer que la salida golpee un archivo y luego enviarlo por correo.


2
Como mencionó geekosaur, && no debería usarse aquí porque el valor de retorno de grep depende de si encontró algo o no. Si lo hiciera grep ... && bzgrep ..., si grep no tuvo aciertos, devolvería el error y el comando se detendría. >>Sin embargo, es una buena idea, a diferencia de >, agregará salida al final de un archivo existente.
DerfK

Bien, me había olvidado de la condición de salida que impedía el segundo comando.
Mike
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.