En un script bash, me gustaría capturar la salida estándar de un comando largo línea por línea, para que puedan analizarse e informarse mientras el comando inicial aún se está ejecutando. Esta es la forma complicada que puedo imaginar de hacerlo:
# Start long command in a separated process and redirect stdout to temp file
longcommand > /tmp/tmp$$.out &
#loop until process completes
ps cax | grep longcommand > /dev/null
while [ $? -eq 0 ]
do
#capture the last lines in temp file and determine if there is new content to analyse
tail /tmp/tmp$$.out
# ...
sleep 1 s # sleep in order not to clog cpu
ps cax | grep longcommand > /dev/null
done
Me gustaría saber si hay una manera más sencilla de hacerlo.
EDITAR:
Para aclarar mi pregunta, agregaré esto. El longcommand
muestra su estado línea por línea una vez por segundo. Me gustaría captar la salida antes de que se longcommand
complete.
De esta manera, potencialmente puedo matar longcommand
si no proporciona los resultados que espero.
Yo he tratado:
longcommand |
while IFS= read -r line
do
whatever "$line"
done
Pero whatever
(por ejemplo echo
) solo se ejecuta después de longcommand
completarse.
Respuestas:
Simplemente canalice el comando en un
while
bucle. Hay una serie de matices en esto, pero básicamente (enbash
o cualquier shell POSIX):El otro problema principal con esto (aparte de las
IFS
cosas a continuación) es cuando intentas usar variables desde dentro del ciclo una vez que ha terminado. Esto se debe a que el bucle se ejecuta realmente en un sub-shell (solo otro proceso de shell) desde el que no puede acceder a las variables (también finaliza cuando el bucle lo hace, en cuyo punto las variables se han ido por completo. Para evitar esto, tu puedes hacer:Ejemplo de configuración de Hauke
lastpipe
enbash
otra solución.Actualizar
Para asegurarse de que está procesando la salida del comando 'como sucede', puede usar
stdbuf
para configurar el proceso 'stdout
para que esté en línea.Esto configurará el proceso para escribir una línea a la vez en la tubería en lugar de almacenar internamente su salida en bloques. Tenga en cuenta que el programa puede cambiar esta configuración internamente. Se puede lograr un efecto similar con
unbuffer
(parte deexpect
) oscript
.stdbuf
está disponible en los sistemas GNU y FreeBSD, solo afecta elstdio
almacenamiento en búfer y solo funciona para aplicaciones no setuid, no setgid que están vinculadas dinámicamente (ya que utiliza un truco LD_PRELOAD).fuente
IFS=
no es necesariobash
, lo comprobé después de la última vez.line
(en cuyo caso el resultado se coloca$REPLY
sin los espacios iniciales y finales recortados). Prueba:echo ' x ' | bash -c 'read line; echo "[$line]"'
y compara conecho ' x ' | bash -c 'IFS= read line; echo "[$line]"'
oecho ' x ' | bash -c 'read; echo "[$REPLY]"'
fuente