web-dev-qa-db-fra.com

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

Est-il possible de réactiver un processus suspendu à 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, depuis lors, la dernière commande n’est pas exécutée et vous resterez fatigué.

Existe-t-il un moyen de réactiver le processus depuis sleep ou peut-être 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.

27
Bittenus

Lorsqu'un script Bash exécute sleepname__, voici à quoi pourrait ressembler pstreename__:

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 sommeil, nous envoyions kill 8506 et la session Bash reprendrait ... Le problème est dans un environnement scripté, nous ne connaissons pas le PID de la commande sleepet 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 les instances de sleepqui sont en cours d’exécution en dessous 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 puis, nous pouvons indiquer pkillà nuke sleepinstances s'exécutant sous ce PID:

pkill -P $(<myscript.pid) sleep

Là encore, cela se limite aux seuls processus sleepexécutés 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 déclencher un processus anysleepsur le système (autorisations accordées).

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

enter image description here


Une autre approche consiste à pousser sleepen arrière-plan, stocker son PID, puis le renvoyer au premier plan. Dans le script:

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

Et pour le tuer:

kill $(<myscript.sleep.pid)
47
Oli

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.
5
afbach

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.

4
animaletdesequia

J'ai un script bash en sommeil 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 les instances sleep. Ceci peut être évité en limitant la recherche à l’aide des options de 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 a 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 et cela tuerait toute la session, qui comprend le shell, notre programme display-auto-brightness et la commande sleep. Au lieu de cela, nous utiliserons kill 26552 pour supprimer uniquement la commande sleep, forçant ainsi notre programme à se réveiller et à régler 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 de lui-même en 1 à 59 secondes, mais il est plus confortable que la luminosité soit réglée instantanément.

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

1
WinEunuuchs2Unix