Presione cualquier tecla para pausar el script de shell, presione nuevamente para continuar

10

He escrito un script de shell para probar una API que copia archivos y hace eco de su progreso después de cada uno.

Hay una suspensión de dos segundos entre cada copia, por lo que me gustaría agregar la capacidad de presionar cualquier tecla para pausar el script y permitir una prueba más profunda. Luego presione cualquier tecla para reanudar.

¿Cómo puedo agregar esto en la menor cantidad de líneas posible?

blarg
fuente

Respuestas:

12

No necesita agregar algo a su script. El shell permite tal funcionalidad.

  • Comience su secuencia de comandos en una terminal.
  • Mientras se está ejecutando y bloqueando el uso del terminal ctrl- z. El terminal se libera nuevamente y verá un mensaje de que el proceso se ha detenido. (Ahora está en estado de proceso T, detenido)
  • Ahora haz lo que quieras. También puede iniciar otros procesos / scripts y detenerlos con ctrl- z.
  • Escriba jobsel terminal o enumere todos los trabajos detenidos.
  • Para permitir que su script continúe, escriba fg(primer plano). Reanuda el trabajo nuevamente en el grupo de procesos en primer plano y los trabajos continúan ejecutándose.

Ver un ejemplo:

root@host:~$ sleep 10 # sleep for 10 seconds
^Z
[1]+  Stopped                 sleep 10
root@host:~$ jobs # list all stopped jobs
[1]+  Stopped                 sleep 10
root@host:~$ fg # continue the job
sleep 10
root@host:~$ # job has finished
caos
fuente
como dijiste, si corro sleep 10; notify-send helloy presiono CTRL + Z para detener, notify-send hellome ejecutan. si se ejecuta el segundo comando, ¿cómo se detiene el primer proceso? después de eso si el tipo fgno puedo ver que ocurra algo, lo cual es obvio, ya que el segundo comando ya está ejecutado
Edward Torvalds
@edwardtorvalds porque los dos comandos están separados. En un guión, deberían estar en una subshell. Escríbalos en un script simple y ejecute el script. Luego ctrl-z para detener y verá que el segundo comando no se ejecuta hasta que el primero haya terminado. Escribir cmd; cmd; cmd;es como escribir cmd <newline> cmd <newline> .... Como alternativa a una secuencia de comandos puede escribir ( cmd; cmd; cmd; ), que se comportaría como el guión, bacuse del subnivel generada por(
el caos
También lo intenté sleep 10. cuando presiono CTRL + Z después de 3 segundos y reanudo después de unos segundos y noté que el comando de suspensión murió en menos de 7 segundos. que es opuesto a lo que dijiste, ya que el comando nunca se detiene, simplemente se ejecuta en segundo plano.
Edward Torvalds
@edwardtorvalds También noté eso ... No tiene sentido. I straceD del sleepmando y descubrí que la llamada al sistema utilizado es nanosleep(). Parece ser un comportamiento definido de la nanosleepllamada al sistema. restart_syscall()reinicia la llamada interrumpida del sistema con un argumento de tiempo que se ajusta adecuadamente para tener en cuenta el tiempo que ya ha transcurrido (incluido el tiempo en que el proceso fue detenido por una señal). Lea esa página de manual
caos
Varias notas para completar la respuesta @chaos (siéntase libre de incluirlas): cuando se hace Ctrl-Z, el trabajo se suspende ("detiene"), por lo que no se está ejecutando en este momento, esperando que decida continuar. en primer plano (ej . fg %1:) o en el fondo (ej bg %1.:). (si los trabajos solo dan 1 número, es decir, solo 1 proceso suspendido, como se muestra en el ejemplo de caos: solo [1]+ stopped sleep 10, puede omitir la %nparte. Si hay varios procesos en segundo plano (en ejecución o detenidos), debe designar el que desea con: %n(por ejemplo: fg %2 tener% 2 currículum en primer plano))
Olivier Dulac
6

Si solo desea pausar el guión mientras permanece dentro del guión, puede usar leer en lugar de dormir.

Puedes usar

read -tpara establecer un tiempo de espera para que la lectura
read -nlea un carácter (efectivamente, simplemente presione cualquier tecla) para continuar la secuencia de comandos

Como no ha proporcionado ningún código, a continuación se muestra un ejemplo de cómo podría usarse.
Si se presiona q, entonces read -n1evita que el script continúe hasta que se presiona una tecla.
Cuando se presiona una tecla, la verificación se restablece y el script continúa en el bucle como de costumbre.

while [[ true ]]; do
    read -t2 -n1 check
    if [[ $check == "q" ]];then
        echo "pressed"
        read -n1
        check=""
    else
        echo "not pressed"
    fi
echo "Doing Something"
done

También puede agregar stty -echoal inicio de la sección y stty echoal final para evitar que la escritura estropee la salida de la pantalla


fuente
@mikeserv No creo que a op le importe lo que se lee, solo quieren pausar y reanudar el script, a qué te refieres con guardar la configuración del terminal también, solo estoy cambiando una, por lo que parece un poco exagerado.
1
@mikeserv ahh cierto, estaba suponiendo que todo el stdin provendría del usuario.
1

Con ddusted puede leer de manera confiable un solo byte de un archivo. Con sttyusted puede establecer un minnúmero de bytes para calificar una lectura de terminal y una timesalida en décimas de segundo. Combina esos dos y puedes prescindir por sleepcompleto, creo, y solo deja que el tiempo de espera de lectura del terminal haga el trabajo por ti:

s=$(stty -g </dev/tty)
(while stty raw -echo isig time 20 min 0;test -z "$(
dd bs=1 count=1 2>/dev/null; stty "$s")" || (exec sh)
do echo "$SECONDS:" do your stuff here maybe                             
   echo  no sleep necessary, I think                                                          
   [ "$((i+=1))" -gt 10 ] && exit                                                             
done       
) </dev/tty

Ese es un pequeño whilebucle de ejemplo que me burlé para que lo pruebes. Cada dos segundos ddagota su intento de lectura de stdin- redirigido desde /dev/tty- y los whilebucles de bucle. Eso o dd no expira porque presiona una tecla, en cuyo caso se invoca un shell interactivo.

Aquí hay una prueba de funcionamiento: los números impresos en la cabecera de cada línea son el valor de la variable de shell $SECONDS:

273315: do your stuff here maybe
no sleep necessary, I think
273317: do your stuff here maybe
no sleep necessary, I think
273319: do your stuff here maybe
no sleep necessary, I think
273321: do your stuff here maybe
no sleep necessary, I think
sh-4.3$ : if you press a key you get an interactive shell
sh-4.3$ : this example loop quits after ten iterations
sh-4.3$ : or if this shell exits with a non-zero exit status
sh-4.3$ : and speaking of which, to do so you just...
sh-4.3$ exit
exit
273385: do your stuff here maybe
no sleep necessary, I think
273387: do your stuff here maybe
no sleep necessary, I think
273389: do your stuff here maybe
no sleep necessary, I think
273391: do your stuff here maybe
no sleep necessary, I think
273393: do your stuff here maybe
no sleep necessary, I think
273395: do your stuff here maybe
no sleep necessary, I think
273397: do your stuff here maybe
no sleep necessary, I think
mikeserv
fuente
¿No deberías usar stty sanedespués de cambiar la configuración stty, puedo estar equivocado pero no parece que los reinicies en ningún lado?
@Jidder: no, guardo el estado del terminal en la parte superior del script con s=$(stty -g </dev/tty). Inmediatamente después de llamar, ddlo restauro con stty "$s". El estado del terminal no se preocupa por las subcapas y, por lo tanto, esas configuraciones se mantienen independientemente del shell principal. stty saneno es necesariamente lo que quieres hacer: es mejor restaurar el estado a la forma en que lo encontraste que asumir que el estado estaba saneen ese punto. Si no lo restaurara, eso echoestaría por todas partes. Entender eso es en parte por qué llegué tan tarde: su respuesta no estaba aquí cuando comencé a probar.
mikeserv