Comment puis-je réveiller un script bash endormi?

Est-il possible de réactiver un processus en pause à l’aide de la commande sleep ?


Par exemple, supposons que vous ayez ce script:

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

Au bout de 30 minutes, vous découvrez que vous avez besoin de l’arrêt du script, c’est-à-dire que vous auriez souhaité écrire plutôt sleep 30m .

Vous ne voulez pas appeler kill PID ni appuyer sur Ctrl + C , car la dernière commande n’est pas exécutée et vous restrez fatigué.

Existe-t-il un moyen de sortir du processus de sleep ou d’utiliser une autre commande prenant en charge le réveil? Les solutions aux processus d’arrière-plan et de premier plan sont les bienvenues.

Lorsqu’un script Bash exécute un sleep , voici à quoi pourrait ressembler le pstree :

 bash(10102)───sleep(8506) 

Les deux ont des ID de processus (PID), même lorsqu’ils sont exécutés en tant que script. Si nous voulions interrompre le sumil, nous kill 8506 et la session Bash reprendrait … Le problème est dans un environnement scripté, nous ne connaissons pas le PID de la commande sleep et il n’y a pas d’humain à regarder. à l’arbre de processus.

Nous pouvons obtenir le PID de la session Bash via la variable $$ magique. Si nous pouvons stocker cela quelque part, nous pouvons alors cibler des instances de sleep qui s’exécutent sous ce PID. Voici ce que je mettrais dans le script:

 # write the current session's PID to file echo $$ >> myscript.pid # go to sleep for a long time sleep 1000 

Et ensuite, nous pouvons dire à pkill de neutraliser sleep instances de sleep s’exécutant sous ce PID:

 pkill -P $( 

Encore une fois, cela se limite à ne mettre en sleep processus s’exécutant directement sous cette session Bash. Tant que le PID a été enregistré correctement, cela le rend beaucoup plus sûr que killall sleep ou pkill sleep , ce qui pourrait interrompre n'importe quel processus de sleep sur le système (permissions accordées).

Nous pouvons prouver cette théorie avec l'exemple suivant où nous avons trois sessions distinctes, dont deux en sleep . Seulement parce que nous spécifions le PID de la session bash en haut à gauche, seul son sleep est tué.

entrez la description de l'image ici


Une autre approche consiste à pousser le sleep vers l'arrière-plan, à stocker son PID, puis à le ramener au premier plan. Dans le script:

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

Et pour le tuer:

 kill $( 

Vous pouvez écrire votre script pour gérer (“piéger”) d’autres signaux tels que kill, etc. afin de pouvoir modifier le comportement des scripts si nécessaire. Voir l’homme 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. 

Vous pouvez simplement arrêter de dormir, ce qui passerait à la ligne suivante du script:

 pkill sleep 

Notez que cela tuerait tout processus de veille en cours d’exécution sur votre système, pas seulement dans votre script.

J’ai un script de sumil bash démarré par cron au démarrage. Le script se réveille toutes les minutes et règle la luminosité de l’écran du portable en fonction du lever et du coucher du soleil obtenus sur Internet. Une phase de transition configurable par l’utilisateur entre la luminosité maximale et la luminosité maximale nécessite d’intensifier et de réduire les valeurs de 3, 4, 5 ou ce qui est calculé toutes les minutes.

Oli a brièvement évoqué pstree dans sa réponse, mais l’a rejetée car cela tuerait toutes sleep instances de sleep . Ceci peut être évité en limitant la recherche à l’aide des options pstree.

En utilisant pstree -h nous voyons toute la hiérarchie:

 $ 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 

Comme vous pouvez le constater, une connexion Ubuntu typique contient de nombreux PID (ID de processus).

Nous pouvons le réduire à notre script courant en utilisant:

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

Nous voyons:

  • cron démarré un shell (ID de processus 1308 et ID de session 1308)
  • Le shell appelle notre programme qui s’exécute sous l’ID de processus 1321 et l’ID de session 1308 (correspondant au shell)
  • Notre programme appelle sleep sous l’ID de processus 26552 et à nouveau l’ID de session 1308

À ce stade, nous pouvons utiliser pkill -s 1308 , ce qui tuerait toute la session, y compris le shell, notre programme display-auto-brightness et la commande sleep . Au lieu de cela, nous utiliserons kill 26552 pour ne tuer que la commande sleep, forçant ainsi notre programme à se réveiller et à ajuster la luminosité.

En tapant ceci manuellement dans le terminal, vous voyez:

 ─────────────────────────────────────────────────────────────────────────────── 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:~$ 

L’étape suivante consiste à le faire lorsque l’ordinateur portable sort de suspension. Par exemple, lorsque le couvercle était fermé, il faisait complètement noir et la luminosité de l’écran était réglée sur “300”. Lorsque le couvercle est ouvert, il fait jour et la luminosité doit être réglée sur “2000”. Bien sûr, le programme se réveillerait tout seul en 1 à 59 secondes, mais il est plus confortable de régler la luminosité instantanément.

Je posterai le code de suspension / reprise après l’avoir écrit. Espérons que ce week-end.