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.
Lorsqu'un script Bash exécute sleep
name__, voici à quoi pourrait ressembler pstree
name__:
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 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 les instances de sleep
qui 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 sleep
instances s'exécutant sous ce PID:
pkill -P $(<myscript.pid) sleep
Là encore, cela se limite aux seuls processus sleep
exé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 anysleep
sur 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 sleep
name__. Seulement parce que nous spécifions le PID de la session bash en haut à gauche, seul son sleep
est tué.
Une autre approche consiste à pousser sleep
en 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)
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 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)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.