El timeout
comando GNU coreutils es extremadamente útil para ciertas situaciones de secuencias de comandos, ya que permite utilizar la salida de un comando si se ejecuta rápidamente y omitirlo si lleva demasiado tiempo.
¿Cómo puedo aproximar el comportamiento básico de timeout
usar solo las utilidades POSIX especificadas?
(Estoy pensando que puede implicar una combinación de wait
, sleep
, kill
y quién sabe qué más, pero quizás me falta un enfoque más sencillo.)
shell-script
posix
timeout
Comodín
fuente
fuente
command & pid=$! ; sleep 5 && kill $pid
command
termina rápidamente hay una pequeña posibilidad depid
que otro proceso se vuelva a utilizar antes de que sekill
ejecute el comando? No querría eso en el código de producción ...timeout
programa y usarlo?Respuestas:
Mi enfoque sería este:
Ejecutar comando como proceso en segundo plano 1
Ejecute el "temporizador de vigilancia" como proceso en segundo plano 2
Configure un controlador para atrapar una señal de terminación en el shell principal
Espere a que se completen ambos procesos. El proceso que termina primero, envía la señal de terminación al padre.
El controlador de trampa de los padres mata ambos procesos en segundo plano a través del control de trabajo (uno de ellos ya ha terminado por definición, pero ese asesinato será una operación inofensiva porque no estamos usando PID, ver más abajo)
Traté de eludir la posible condición de carrera abordada en los comentarios mediante el uso de las ID de control de trabajo del shell (que sería inequívoco dentro de esta instancia del shell) para identificar los procesos en segundo plano para matar, en lugar de los PID del sistema.
Resultado para
TIMEOUT=10
(el comando termina antes del watchdog):Resultado para
TIMEOUT=1
(watchdog termina antes del comando):Resultado para
TIMEOUT=5
(watchdog y comando terminan "casi" simultáneamente):fuente
cleanup() { ...; }
y (b) el control del trabajo es una función bash no especificada por POSIX (aunque ksh y otros también lo tienen). Buen guión, sin embargo!timeout="$1"; shift
y en(exec "$@"; echo "Command completed"; kill $$)
lugar de volver a dividir la lista de argumentos.