Tengo un script de shell eso es leer desde una entrada estándar . En raras circunstancias, no habrá nadie listo para proporcionar información y el script debe tiempo de espera. . En caso de tiempo de espera, el script debe ejecutar algún código de limpieza. ¿Cuál es la mejor manera de hacerlo?
Este script debe ser muy portátil , incluidos los sistemas Unix del siglo XX sin un compilador C y los dispositivos integrados que ejecutan busybox, por lo que no se puede confiar en Perl, bash, ningún lenguaje compilado e incluso el POSIX.2 completo. En particular, $PPID
, read -t
y las trampas perfectamente compatibles con POSIX no están disponibles. También se excluye escribir en un archivo temporal; el script puede ejecutarse incluso si todos los sistemas de archivos están montados como de solo lectura.
Solo para hacer las cosas más difíciles, también quiero que el guión sea razonablemente rápido cuando no se agote el tiempo. En particular, también uso el script en Windows (principalmente en Cygwin), donde la bifurcación y la ejecución son particularmente bajas, por lo que quiero mantener su uso al mínimo.
En pocas palabras, tengo
trap cleanup 1 2 3 15
foo=`cat`
y quiero agregar un tiempo de espera. No puedo reemplazar cat
con el read
incorporado. En caso de tiempo de espera, quiero ejecutar cleanup
función.
Antecedentes:este script adivina la codificación del terminal imprimiendo algunos caracteres de 8 bits y comparando la posición del cursor antes y después. El comienzo de la secuencia de comandos prueba que stdout está conectado a un terminal compatible, pero a veces el entorno miente (por ejemplo, plink
establece TERM=xterm
incluso si se llama con TERM=dumb
). La parte relevante del script se ve así:
text='Éé' # UTF-8; shows up as Ãé on a latin1 terminal
csi='␛['; dsr_cpr="${csi}6n"; dsr_ok="${csi}5n" # ␛ is an escape character
stty_save=`stty -g`
cleanup () { stty "$stty_save"; }
trap 'cleanup; exit 120' 0 1 2 3 15 # cleanup code
stty eol 0 eof n -echo # Input will end with `0n`
# echo-n is a function that outputs its argument without a newline
echo-n "$dsr_cpr$dsr_ok" # Ask the terminal to report the cursor position
initial_report=`tr -dc ;0123456789` # Expect ␛[42;10R␛[0n for y=42,x=10
echo-n "$text$dsr_cpr$dsr_ok"
final_report=`tr -dc ;0123456789`
cleanup
# Compute and return initial_x - final_x
¿Cómo puedo modificar el script para que si tr
no ha leído ninguna entrada después de 2 segundos, se elimina y el script ejecuta la cleanup
función?
Respuesta aceptada:
¿Qué pasa con esto:
foo=`{ { cat 1>&3; kill 0; } | { sleep 2; kill 0; } } 3>&1`
Es decir:ejecute el comando de producción de salida y sleep
en el mismo grupo de procesos, un grupo de procesos solo para ellos. Cualquiera que sea el comando que regresa primero, mata todo el grupo de procesos.
Alguien se preguntaría:Sí, la tubería no se usa; se omite usando las redirecciones. El único propósito es que el shell ejecute los dos procesos en el mismo grupo de procesos.
Relacionado:¿Un script para reducir y comprimir imágenes de disco DMG no parece funcionar bien en el escenario?Como señaló Gilles en su comentario, esto no funcionará en un script de shell porque el proceso del script se eliminaría junto con los dos subprocesos.
Una forma¹ de forzar la ejecución de un comando en un grupo de procesos separado es iniciar un nuevo shell interactivo:
#!/bin/sh
foo=`sh -ic '{ cat 1>&3; kill 0; } | { sleep 2; kill 0; }' 3>&1 2>/dev/null`
[ -n "$foo" ] && echo got: "$foo" || echo timeouted
Pero puede haber advertencias con esto (por ejemplo, ¿cuándo stdin no es un tty?). La redirección stderr está ahí para deshacerse del mensaje "Terminado" cuando se elimina el shell interactivo.
Probado con zsh
,bash
y dash
. Pero ¿qué pasa con los viejos?
B98 sugiere el siguiente cambio, trabajando en Mac OS X, con GNU bash 3.2.57 o Linux con guión:
foo=`sh -ic 'exec 3>&1 2>/dev/null; { cat 1>&3; kill 0; } | { sleep 2; kill 0; }'`
–