escribir a fifo / pipe desde shell, con timeout
-
05-07-2019 - |
Pregunta
Tengo un par de programas shell que hablan sobre una canalización con nombre. El lector crea el canal cuando se inicia y lo elimina cuando sale.
A veces, el escritor intentará escribir en la tubería entre el momento en que el lector deja de leer y la hora en que se quita la tubería.
reader: while condition; do read data <$PIPE; do_stuff; done
writer: echo $data >>$PIPE
reader: rm $PIPE
cuando esto suceda, el escritor se colgará para siempre intentando abrir el conducto para escribir.
¿Hay una forma limpia de darle un tiempo de espera, para que no se cuelgue hasta que se elimine manualmente? Sé que puedo hacer
#!/bin/sh
# timed_write <timeout> <file> <args>
# like "echo <args> >> <file>" with a timeout
TIMEOUT=$1
shift;
FILENAME=$1
shift;
PID=$
(X=0; # don't do "sleep $TIMEOUT", the "kill %1" doesn't kill the sleep
while [ "$X" -lt "$TIMEOUT" ];
do sleep 1; X=$(expr $X + 1);
done; kill $PID) &
echo "$@" >>$FILENAME
kill %1
pero esto es un poco desagradable. ¿Hay un shell incorporado o un comando para hacerlo de forma más limpia (sin romper el compilador de C)?
Solución 3
Este par de programas funciona mucho mejor después de ser reescrito en Perl usando sockets de dominio Unix en lugar de canales con nombre. El problema particular en esta pregunta desapareció por completo, ya que si / cuando un extremo muere, la conexión desaparece en lugar de colgarse.
Otros consejos
El UNIX " estándar " La forma de lidiar con esto es usar Expect , que viene con un ejemplo de ejecución cronometrada: ejecute un programa por solo una cantidad de tiempo dada.
Esperar puede hacer maravillas para los scripts, vale la pena aprenderlo. Si no te gusta Tcl, también hay un módulo Python Expect .
Esta pregunta surge periódicamente (aunque no pude encontrarla con una búsqueda). He escrito dos scripts de shell para usar como comandos de tiempo de espera: uno para cosas que leen entrada estándar y otro para cosas que no leen entrada estándar. Esto apesta, y he tenido la intención de escribir un programa en C, pero todavía no he llegado a eso. Definitivamente recomiendo escribir un comando de timeout
en C de una vez por todas. Pero mientras tanto, aquí está el más simple de los dos scripts de shell, que se cuelga si el comando lee la entrada estándar:
#!/bin/ksh
# our watchdog timeout in seconds
maxseconds="$1"
shift
case $# in
0) echo "Usage: `basename <*>` <seconds> <command> [arg ...]" 1>&2 ;;
esac
"$@" &
waitforpid=$!
{
sleep $maxseconds
echo "TIMED OUT: $@" 1>&2
2>/dev/null kill -0 $waitforpid && kill -15 $waitforpid
} &
killerpid=$!
>>/dev/null 2>&1 wait $waitforpid
# this is the exit value we care about, so save it and use it when we
rc=$?
# zap our watchdog if it's still there, since we no longer need it
2>>/dev/null kill -0 $killerpid && kill -15 $killerpid
exit $rc
El otro script está en línea en http: //www.cs.tufts. edu / ~ nr / drop / timeout .
trap 'kill $(ps -L $! -o pid=); exit 30' 30
echo kill -30 $ 2\>/dev/null | at $1 2>/dev/null
shift; eval $@ &
wait