scripts script programas programacion pasar parametros operaciones manejo español ejemplos comandos cadenas aritmeticas linux bash shell

linux - script - ¿Cómo ejecuto un comando en un bucle hasta que veo alguna cadena en stdout?



scripts bash ejemplos (8)

EDITAR: Mi respuesta original fue asumir que "una cadena" significa "cualquier cadena". Si necesita buscar uno específico, Perl es probablemente su mejor opción, ya que casi nada puede vencer a Perl en lo que respecta a la coincidencia de REGEX.

Sin embargo, si no puede usar Perl por algún motivo (puede esperar que Perl esté presente en la mayoría de las distribuciones de Linux, pero nadie obliga al usuario a instalarlo, aunque Perl puede no estar disponible), puede hacerlo con la ayuda de grep. Sin embargo, algunas de las soluciones grep que he visto hasta ahora son subóptimas (son más lentas de lo que sería necesario). En ese caso, preferiría hacer lo siguiente:

MATCH=''''; while [[ "e$MATCH" == "e" ]]; do MATCH=`COMMAND | grep "SOME_STRING"`; done; echo $MATCH

Reemplace COMMAND con el comando actual para ejecutar y SOME_STRING con la cadena para buscar. Si SOME_STRING se encuentra en la salida de COMMAND, el ciclo se detendrá e imprimirá el resultado donde se encontró SOME_STRING.

RESPUESTA ORIGINAL:

Probablemente no sea la mejor solución (no soy un buen programador de bash), pero funcionará :-P

RUN=''''; while [[ "e$RUN" == "e" ]]; do RUN=`XXXX`; done ; echo $RUN

Simplemente reemplace XXXX con su llamada de comando, por ejemplo, intente usar " eco " y nunca regresará (ya que el eco nunca imprime nada en la salida estándar); sin embargo, si usa " prueba de eco " terminará de una vez y finalmente imprimirá la prueba.

Estoy seguro de que hay un trazador de líneas trivial con perl, ruby, bash, lo que sea que me permita ejecutar un comando en un bucle hasta que observe una cuerda en stdout, luego me detengo. Idealmente, me gustaría capturar stdout también, pero si va a la consola, eso podría ser suficiente.

El entorno particular en cuestión en este momento es RedHat Linux, pero también lo mismo en Mac. Entonces algo, genérico y * nixy sería lo mejor. No me importa Windows, presumiblemente una cosa * nixy funcionaría bajo cygwin.

ACTUALIZACIÓN: Tenga en cuenta que al "observar una cadena" quiero decir "stdout contiene algo de cadena", no "stdout IS some string".


En Perl:

#!/usr/local/bin/perl -w if (@ARGV != 2) { print "Usage: watchit.pl <cmd> <str>/n"; exit(1); } $cmd = $ARGV[0]; $str = $ARGV[1]; while (1) { my $output = `$cmd`; print $output; # or dump to file if desired if ($output =~ /$str/) { exit(0); } }

Ejemplo:

[bash$] ./watchit.pl ls stop watchit.pl watchit.pl~ watchit.pl watchit.pl~ ... # from another terminal type "touch stop" stop watchit.pl watchit.pl~

Sin embargo, es posible que desee agregar un sueño.


Hay muchas maneras de hacerlo, lo primero que me vino a la mente fue:

OUTPUT=""; while [ `echo $OUTPUT | grep -c somestring` = 0 ]; do OUTPUT=`$cmd`; done

Donde $ cmd es tu comando para ejecutar.

Por si fuera poco, aquí hay una versión de la función BASH, por lo que puede llamar esto más fácilmente si es algo que desea invocar desde un shell interactivo de forma regular:

function run_until () { OUTPUT=""; while [ `echo $OUTPUT | grep -c $2` = 0 ]; do OUTPUT=`$1`; echo $OUTPUT; done }

Descargo de responsabilidad: solo se ha probado ligeramente, es posible que tenga que realizar escapes adicionales, etc., si sus comandos tienen muchos argumentos o si la cadena contiene caracteres especiales.

EDITAR : basado en la retroalimentación del comentario de Adam: si no necesita la salida por algún motivo (es decir, no desea mostrar la salida), puede usar esta versión más corta, con menos uso de backticks y, por lo tanto, menos sobrecarga:

OUTPUT=0; while [ "$OUTPUT" = 0 ]; do OUTPUT=`$cmd | grep -c somestring`; done

Versión de la función BASH también:

function run_until () { OUTPUT=0; while [ "$OUTPUT" = 0 ]; do OUTPUT=`$1 | grep -c $2`; done }


while (/bin/true); do OUTPUT=`/some/command` if [[ "x$OUTPUT" != "x" ]]; then echo $OUTPUT break fi sleep 1 done


Una forma simple de hacer esto sería

until `/some/command` do sleep 1 done

Los retrocesos alrededor del comando hacen que la prueba until que se devuelva algún resultado en lugar de probar el valor de salida del comando.


grep -c 99999 imprimirá 99999 líneas de contexto para la coincidencia (supongo que esto será suficiente):

while true; do /some/command | grep expected -C 99999 && break; done

o

until /some/command | grep expected -C 9999; do echo -n .; done

... esto imprimirá algunos buenos puntos para indicar el progreso.


Me sorprende que no haya visto una breve frase de Perl mencionada aquí:

perl -e ''do { sleep(1); $_ = `command`; print $_; } until (m/search/);''

Perl es un lenguaje realmente agradable para cosas como esta. Reemplace "comando" con el comando que desea ejecutar repetidamente. Reemplaza "buscar" con lo que deseas buscar. Si desea buscar algo con una barra inclinada, reemplace m/search/ con m#search cadena de m#search con /es# .

Además, Perl se ejecuta en muchas plataformas diferentes, incluida Win32, y esto funcionará donde sea que tenga una instalación de Perl. Solo cambia tu comando apropiadamente.


CONT=1; while [ $CONT -gt 0 ]; do $CMD | tee -a $FILE | grep -q $REGEXP; CONT=$? ; done

El comando tee puede capturar stdout en una tubería mientras todavía se pasan los datos, y -a hace agregar al archivo en lugar de sobrescribirlo cada vez. grep -q return 0 si hubo una coincidencia, 1 caso contrario y no escribe nada en stdout. $? es el valor de retorno del comando anterior, por lo que $CONT será el valor de retorno de grep en este caso.