"Mira" la salida de un comando hasta que se observa una cadena particular y luego sale

29

Estoy buscando una manera de mirar programáticamente la salida de un comando hasta que se observe una cadena en particular y luego salga. Esto es muy similar a esta pregunta, pero en lugar de seguir un archivo, quiero 'seguir' un comando.

Algo como:

reloj -n1 my_cmd | grep -m 1 "Cadena que estoy buscando"

(Pero esto no funciona para mí).

ACTUALIZACIÓN: necesito aclarar que 'my_cmd' no genera texto de forma continua, sino que debe llamarse repetidamente hasta que se encuentre la cadena (por eso pensé en el comando 'watch'). A este respecto, 'my_cmd' es como muchos otros comandos de Unix como: ps, ls, lsof, last, etc.

gdw2
fuente
Hubiera pensado que era posible tail -funa salida del programa tan bien como un archivo ... ¿Me equivoco?
Joanis
@Joanis. Tiene razón, pero en mi caso 'my_cmd' no produce resultados continuamente y debe ser llamado repetidamente (al igual que la mayoría de los comandos: ps, ls, lsof, etc.)
gdw2

Respuestas:

41

Usa un bucle:

until my_cmd | grep -m 1 "String Im Looking For"; do : ; done

En lugar de :, puede usar sleep 1(o 0.2) para facilitar la CPU.

El ciclo se ejecuta hasta que grep encuentra la cadena en la salida del comando. -m 1significa "una coincidencia es suficiente", es decir, grep deja de buscar después de encontrar la primera coincidencia.

También puede usar grep -qque también se cierra después de encontrar la primera coincidencia, pero sin imprimir la línea coincidente.

choroba
fuente
Se agradecería una explicación de este comando.
Mark W
@ MarkW: Actualizado.
choroba
alguien más mencionó grep -qcuál es otra opción. grep se cierra después de encontrar la cadena.
Dom
tenga en cuenta que este comando ejecutará repetidamente el comando en cuestión, lo que podría o no ser deseable.
Adrien
1
@A__: Es deseable, como se indica en el OP en "Actualización".
choroba
11
watch -e "! my_cmd | grep -m 1 \"String Im Looking For\""
  • ! niega el código de salida de la tubería de comando
  • grep -m 1 sale cuando se encuentra la cadena
  • watch -e devuelve si ha ocurrido algún error

Pero esto se puede mejorar para mostrar realmente esa línea coincidente, que se ha descartado hasta ahora.

mates
fuente
Gracias por la explicación detallada, pero no me funciona. Mi watchcomando (CentOS) no tiene la -ebandera (que realmente no debería importar). Sin embargo, lo más importante es que cuando se encuentra la cadena, el reloj continúa ejecutándose y no sale. Parece que cuando grep -msale, solo sale mata my_cmd, pero no watch.
gdw2
¡No, sí importa! El indicador "-e" está indicado para abandonar el reloj cuando el comando tiene un código de error diferente de 0. Dado que su reloj no presente está a punto de continuar en su plataforma. De todos modos, es bueno saberlo, en mi instalación de Ubuntu 11.10 todo está bien. A veces también tengo problemas con Mac OSX con respecto a herramientas de línea de comandos muy anticuadas y estoy usando puertos mac hasta ahora para obtener un software más actual.
matemáticas
Esto se detiene si se encuentra el patrón, pero no muestra ningún resultado hasta que eso sucede
Mark
Puede emplear teepara eso, pero esto introduce una nueva línea engañosa, no sé cómo eludir en este momento:watch -n1 -e "! date | tee /dev/tty | grep --color -m 1 \"17\""
matemáticas
Sí, esto no funcionó para mí. watchobedientemente deja de mirar cuando se encuentra la cadena, pero en realidad no sale hasta que presiona una tecla. Tan cerca.
mlissner
8

Para aquellos que tienen un programa que escribe continuamente en stdout, todo lo que necesita hacer es canalizarlo a grep con la opción de 'coincidencia única'. Una vez que grep encuentre la cadena coincidente, saldrá, lo que cierra stdout en el proceso que se está canalizando a grep. Este evento debería hacer que el programa salga con gracia siempre que el proceso vuelva a escribir .

Lo que sucederá es que el proceso recibirá un SIGPIPE cuando intente escribir en stdout cerrado después de que grep haya salido. Aquí hay un ejemplo con ping, que de otro modo se ejecutaría indefinidamente:

$ ping superuser.com | grep -m 1 "icmp_seq"

Este comando coincidirá con el primer 'pong' exitoso y luego saldrá la próxima vez que pingintente escribir en stdout.


Sin embargo,

No siempre se garantiza que el proceso volverá a escribir en stdout y, por lo tanto, podría no provocar que se genere un SIGPIPE (por ejemplo, esto puede suceder cuando se sigue un archivo de registro). La mejor solución que he logrado encontrar para este escenario implica escribir en un archivo; comente si cree que puede mejorar:

$ { tail -f log_file & echo $! > pid; } | { grep -m1 "find_me" && kill -9 $(cat pid) && rm pid; }

Desglosando esto:

  1. tail -f log_file & echo $! > pid- sigue un archivo, adjunta el proceso al fondo y guarda el PID ( $!) en un archivo. Intenté exportar el PID a una variable, pero parece que hay una condición de carrera entre aquí y cuando el PID se usa nuevamente.
  2. { ... ;}- Agrupe estos comandos para que podamos canalizar la salida a grep manteniendo el contexto actual (ayuda al guardar y reutilizar variables, pero no fue capaz de hacer que esa parte funcione)
  3. | - canaliza el stdout del lado izquierdo al stdin del lado derecho
  4. grep -m1 "find_me" - encuentra la cadena objetivo
  5. && kill -9 $(cat pid)- force kill (SIGKILL) el tailproceso después de grep salir una vez que encuentra la cadena coincidente
  6. && rm pid - eliminar el archivo que creamos
Blake Regalia
fuente
0
my_cmd | tail +1f | sed '/String Im Looking For/q'

Si tailno admite la +1fsintaxis, intente tail -f -n +1. (El -n +1le dice que comience desde el principio; tail -fpor defecto comienza con las últimas 10 líneas de salida).

Keith Thompson
fuente
Por favor vea mi actualización a la pregunta.
gdw2
0

Agregue el resultado de sus llamadas de programa a un archivo. Entonces tail -fese archivo. De esa manera debería funcionar ... espero.

Cuando reinicie la llamada a ese programa, tendrá que borrar el archivo o agregarle algunas tonterías para que no vuelva a coincidir de inmediato con lo que estaba buscando.

Joanis
fuente