¿Cómo puedo despertar un script de bash para dormir?


27

¿Es posible activar un proceso que está en pausa usando el sleepcomando?


Como ejemplo, supongamos que tiene este script:

#!/bin/bash
echo "I am tired"
sleep 8h
echo "I am fresh :)"

Después de 30 minutos, descubre que necesita que el script se detenga, es decir, desea haber escrito en su sleep 30mlugar.

No desea llamar kill PIDni presionar Ctrl+ C, ya que el último comando no se ejecuta y permanecerá cansado.

¿Hay alguna manera de activar el proceso sleepo quizás usar otro comando que admita la activación? Las soluciones para los procesos en segundo plano y en primer plano son bienvenidas


13
Grítalo muy fuerte.
Pomo

2
@Doorknob gawking realmente no funciona. La última vez que tuve un sleepproceso, pushdlo levanté de la cama.
imallett

A tu script le falta una #!línea. Y eso es importante porque la respuesta a su pregunta depende de si hay alguna -een la #!línea.
kasperd

1
@kasperd Hecho. Por curiosidad: ¿qué influencia tiene la bandera -e?
Bittenus

2
Por defecto, un script continuará después de un error. Si lo usa #!/bin/bash -e, el script se detendrá después de un error. Bash matará simplemente el comando de suspensión como un error. Eso significa que sin -euna respuesta bastante simple a su pregunta. Si -ese usó, entonces se vuelve mucho más difícil porque tendrías que detener el proceso de sueño sin matarlo.
kasperd

Respuestas:


47

Cuando se ejecuta un script Bash sleep, esto es lo que pstreepodría parecer:

bash(10102)───sleep(8506)

Ambos tienen ID de proceso (PID), incluso cuando se ejecutan como un script. Si quisiéramos interrumpir el sueño, lo enviaríamos kill 8506y la sesión de Bash se reanudaría ... El problema está en un entorno programado, no conocemos el PID del sleepcomando y no hay un humano para mirar el proceso árbol.

Podemos obtener el PID de la sesión Bash a través de la $$variable mágica. Si podemos almacenar eso en algún lugar, podemos dirigirnos a instancias de sleepeso que se ejecutan debajo de ese PID. Esto es lo que pondría en el guión:

# write the current session's PID to file
echo $$ >> myscript.pid

# go to sleep for a long time
sleep 1000

Y luego podemos decirle pkilla las sleepinstancias nucleares que se ejecutan debajo de ese PID:

pkill -P $(<myscript.pid) sleep

Nuevamente, esto se limita a los sleepprocesos que se ejecutan directamente en esa única sesión Bash. Siempre que el PID se haya registrado correctamente, esto lo hace mucho más seguro que killall sleepo pkill sleep, lo que podría destruir cualquier sleep proceso en el sistema (si los permisos lo permiten).

Podemos probar esa teoría con el siguiente ejemplo donde tenemos tres sesiones bash separadas, dos en ejecución sleep. Solo porque estamos especificando el PID de la sesión bash superior izquierda, solo sleepse elimina.

ingrese la descripción de la imagen aquí


Un enfoque alternativo es sleeppasar al fondo, almacenar su PID y luego devolverlo al primer plano. En el guión:

sleep 1000 &
echo $! > myscript.sleep.pid
fg

Y para matarlo:

kill $(<myscript.sleep.pid)

5

Puede escribir su script para manejar ("atrapar") otras señales de kill, etc. para poder modificar el comportamiento de los scripts según sea necesario. Ver hombre bash:

SIGNALS
   When  bash  is  interactive,  in the absence of any traps, it ignores SIGTERM (so that kill 0 does not
   kill an interactive shell), and SIGINT is caught and handled (so that the wait builtin  is  interrupt-
   ible).   In all cases, bash ignores SIGQUIT.  If job control is in effect, bash ignores SIGTTIN, SIGT-
   TOU, and SIGTSTP.

   Non-builtin commands run by bash have signal handlers set to the values inherited by  the  shell  from
   its  parent.   When  job  control is not in effect, asynchronous commands ignore SIGINT and SIGQUIT in
   addition to these inherited handlers.  Commands run as a result of  command  substitution  ignore  the
   keyboard-generated job control signals SIGTTIN, SIGTTOU, and SIGTSTP.

   The shell exits by default upon receipt of a SIGHUP.  Before exiting, an interactive shell resends the
   SIGHUP to all jobs, running or stopped.  Stopped jobs are sent SIGCONT to ensure that they receive the
   SIGHUP.   To  prevent the shell from sending the signal to a particular job, it should be removed from
   the jobs table with the disown builtin (see SHELL BUILTIN COMMANDS below) or  marked  to  not  receive
   SIGHUP using disown -h.

   If  the huponexit shell option has been set with shopt, bash sends a SIGHUP to all jobs when an inter-
   active login shell exits.

   If bash is waiting for a command to complete and receives a signal for which a trap has been set,  the
   trap  will not be executed until the command completes.  When bash is waiting for an asynchronous com-
   mand via the wait builtin, the reception of a signal for which a trap has been set will cause the wait
   builtin  to  return immediately with an exit status greater than 128, immediately after which the trap
   is executed.

4

Podrías matar el sueño que continuaría con la siguiente línea del script:

pkill sleep

Tenga en cuenta que esto eliminaría cualquier proceso de suspensión que se ejecute en su sistema, no solo en su secuencia de comandos.


1

Tengo un script de bash para dormir iniciado en cronel arranque. El guión se despierta cada minuto y establece el brillo de la pantalla de la computadora portátil en función del amanecer y el atardecer obtenidos de Internet. Una fase de transición configurable por el usuario entre brillo total y atenuación completa requiere aumentar y disminuir los valores en 3, 4, 5 o lo que se calcule cada minuto.

Oli mencionó brevemente pstreesu respuesta pero la rechazó porque mataría todas las sleepinstancias. Esto se puede evitar al restringir la búsqueda utilizando las opciones de pstree.

Usando pstree -hvemos toda la jerarquía:

$ pstree -h
systemd─┬─ModemManager─┬─{gdbus}
                      └─{gmain}
        ├─NetworkManager─┬─dhclient
                        ├─dnsmasq
                        ├─{gdbus}
                        └─{gmain}
        ├─accounts-daemon─┬─{gdbus}
                         └─{gmain}
        ├─acpid
        ├─agetty
        ├─atd
        ├─avahi-daemon───avahi-daemon
        ├─cgmanager
        ├─colord─┬─{gdbus}
                └─{gmain}
        ├─cron───cron───sh───display-auto-br───sleep
        ├─cups-browsed─┬─{gdbus}
                      └─{gmain}
        ├─dbus-daemon
        ├─fwupd─┬─3*[{GUsbEventThread}]
               ├─{fwupd}
               ├─{gdbus}
               └─{gmain}
        ├─gnome-keyring-d─┬─{gdbus}
                         ├─{gmain}
                         └─{timer}
        ├─irqbalance
        ├─lightdm─┬─Xorg───3*[{Xorg}]
                 ├─lightdm─┬─upstart─┬─at-spi-bus-laun─┬─dbus-daemon
                                                    ├─{dconf worker}
                                                    ├─{gdbus}
                                                    └─{gmain}
                                   ├─at-spi2-registr─┬─{gdbus}
                                                    └─{gmain}
                                   ├─bamfdaemon─┬─{dconf worker}
                                               ├─{gdbus}
                                               └─{gmain}
                                   ├─chrome─┬─2*[cat]
                                           ├─chrome─┬─chrome─┬─2*[chrome─┬─{Chrome_ChildIOT}]
                                                                      ├─5*[{CompositorTileW}]]
                                                                      ├─{Compositor}]
                                                                      ├─{GpuMemoryThread}]
                                                                      ├─{MemoryInfra}]
                                                                      ├─{Renderer::FILE}]
                                                                      ├─{TaskSchedulerRe}]
                                                                      └─{TaskSchedulerSe}]
                                                           ├─7*[chrome─┬─{Chrome_ChildIOT}]
                                                                      ├─5*[{CompositorTileW}]]
                                                                      ├─{Compositor}]
                                                                      ├─{GpuMemoryThread}]
                                                                      ├─{MemoryInfra}]
                                                                      ├─{Renderer::FILE}]
                                                                      ├─{ScriptStreamerT}]
                                                                      ├─{TaskSchedulerRe}]
                                                                      └─{TaskSchedulerSe}]
                                                           ├─chrome─┬─{Chrome_ChildIOT}
                                                                   ├─5*[{CompositorTileW}]
                                                                   ├─{Compositor}
                                                                   ├─{GpuMemoryThread}
                                                                   ├─{Media}
                                                                   ├─{MemoryInfra}
                                                                   ├─{Renderer::FILE}
                                                                   ├─{ScriptStreamerT}
                                                                   ├─{TaskSchedulerRe}
                                                                   └─{TaskSchedulerSe}
                                                           └─2*[chrome─┬─{Chrome_ChildIOT}]
                                                                       ├─5*[{CompositorTileW}]]
                                                                       ├─{Compositor}]
                                                                       ├─{GpuMemoryThread}]
                                                                       ├─{Renderer::FILE}]
                                                                       ├─{ScriptStreamerT}]
                                                                       ├─{TaskSchedulerRe}]
                                                                       └─{TaskSchedulerSe}]
                                                   └─nacl_helper
                                           ├─chrome─┬─chrome
                                                   ├─{Chrome_ChildIOT}
                                                   ├─{MemoryInfra}
                                                   ├─{TaskSchedulerSe}
                                                   └─{Watchdog}
                                           ├─{AudioThread}
                                           ├─{BrowserWatchdog}
                                           ├─{Chrome_CacheThr}
                                           ├─{Chrome_DBThread}
                                           ├─{Chrome_FileThre}
                                           ├─{Chrome_FileUser}
                                           ├─{Chrome_HistoryT}
                                           ├─{Chrome_IOThread}
                                           ├─{Chrome_ProcessL}
                                           ├─{Chrome_SyncThre}
                                           ├─{CompositorTileW}
                                           ├─{CrShutdownDetec}
                                           ├─{D-Bus thread}
                                           ├─{Geolocation}
                                           ├─{IndexedDB}
                                           ├─{LevelDBEnv}
                                           ├─{MemoryInfra}
                                           ├─{NetworkChangeNo}
                                           ├─{Networking Priv}
                                           ├─4*[{TaskSchedulerBa}]
                                           ├─6*[{TaskSchedulerFo}]
                                           ├─{TaskSchedulerSe}
                                           ├─{WorkerPool/3166}
                                           ├─{WorkerPool/5824}
                                           ├─{WorkerPool/5898}
                                           ├─{WorkerPool/6601}
                                           ├─{WorkerPool/6603}
                                           ├─{WorkerPool/7313}
                                           ├─{chrome}
                                           ├─{dconf worker}
                                           ├─{extension_crash}
                                           ├─{gdbus}
                                           ├─{gmain}
                                           ├─{gpu-process_cra}
                                           ├─{inotify_reader}
                                           ├─{renderer_crash_}
                                           ├─{sandbox_ipc_thr}
                                           └─{threaded-ml}
                                   ├─compiz─┬─{dconf worker}
                                           ├─{gdbus}
                                           ├─{gmain}
                                           └─8*[{pool}]
                                   ├─conky───6*[{conky}]
                                   ├─2*[dbus-daemon]

( .... many lines deleted to fit in 30k limit .... )

        ├─vnstatd
        ├─whoopsie─┬─{gdbus}
                  └─{gmain}
        └─wpa_supplicant

Como puede ver, un inicio de sesión típico de Ubuntu contiene muchos PID (ID de proceso).

Podemos reducirlo a nuestro script en ejecución usando:

$ pstree -g -p | grep display-auto
  |-cron(1198,1198)---cron(1257,1198)---sh(1308,1308)---display-auto-br(1321,1308)---sleep(26552,1308)

Vemos:

  • cron inició un shell (ID de proceso 1308 e ID de sesión 1308)
  • El shell llama a nuestro programa que se ejecuta con el ID de proceso 1321 y el ID de sesión 1308 (que coincide con el shell)
  • Nuestro programa llama sleepbajo ID de proceso 26552 y nuevamente ID de sesión 1308

En este punto, podemos usar pkill -s 1308y mataría toda la sesión, que incluye el shell, nuestro programa display-auto-brightnessy el sleepcomando. En su lugar, usaremos kill 26552solo para matar el comando de suspensión, lo que obligará a nuestro programa a despertarse y ajustar el brillo.

Escribiendo esto manualmente en el terminal que ves:

───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ pstree -g -p | grep display-auto
             |-cron(1198,1198)---cron(1257,1198)---sh(1308,1308)---display-auto-br(1321,1308)---sleep(32362,1308)
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ sudo kill 32362
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ pstree -g -p | grep display-auto
             |-cron(1198,1198)---cron(1257,1198)---sh(1308,1308)---display-auto-br(1321,1308)---sleep(1279,1308)
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ sudo kill 1279
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ pstree -g -p | grep display-auto
             |-cron(1198,1198)---cron(1257,1198)---sh(1308,1308)---display-auto-br(1321,1308)---sleep(4440,1308)
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ 

El siguiente paso es hacerlo cuando la computadora portátil se despierte de la suspensión. Por ejemplo, cuando la tapa se cerró, estaba completamente oscura y el brillo de la pantalla se estableció en "300". Cuando se abre la tapa, es de día y el brillo debe establecerse en "2000". Por supuesto, el programa se activaría por sí solo en 1 a 59 segundos, pero es más cómodo configurar el brillo al instante.

Publicaré el código de suspensión / reanudación después de que esté escrito. Ojalá este fin de semana.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.