Wie kann ich ein schlafendes Bash-Skript aktivieren?

27

Ist es möglich, einen angehaltenen Prozess mit dem sleepBefehl aufzuwecken ?


Nehmen wir als Beispiel an, Sie haben dieses Skript:

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

Nach 30 Minuten stellen Sie fest, dass Sie das Skript zum Stoppen benötigen, das heißt, Sie wünschten, Sie hätten sleep 30mstattdessen geschrieben .

Sie möchten weder anrufen kill PIDnoch Ctrl+ drücken C, da dann der letzte Befehl nicht ausgeführt wird und Sie müde bleiben.

Gibt es eine Möglichkeit, den Prozess von sleepeinem anderen Befehl aufzuwecken oder einen anderen Befehl zu verwenden, der das Aufwecken unterstützt? Lösungen für Hintergrund- und Vordergrundprozesse sind willkommen.

Bittenus
quelle
13
Schrei es richtig laut an.
Türknauf
2
@Doorknobing gawkfunktioniert nicht wirklich. Das letzte Mal, als ich einen sleepProzess hatte, habe ich pushdihn vom Bett genommen.
Imallett
In Ihrem Skript fehlt eine #!Zeile. Und das ist wichtig, da die Antwort auf Ihre Frage davon abhängt, ob es welche -ein der #!Zeile gibt.
Kasperd
1
@kasperd Fertig. Aus Neugier: Welchen Einfluss hat die -e Flagge?
Bittenus
2
Standardmäßig wird ein Skript nach einem Fehler fortgesetzt. Wenn Sie verwenden #!/bin/bash -e, wird das Skript nach einem Fehler beendet. Das einfache Beenden des Befehls sleep wird von bash als Fehler behandelt. Das heißt, ohne -edass es eine recht einfache Antwort auf Ihre Frage gibt. Wenn -ees verwendet wurde, wird es viel schwieriger, weil Sie den Schlafprozess stoppen müssten, ohne ihn zu töten.
Kasperd

Antworten:

47

Wenn ein Bash-Skript mit a ausgeführt wird sleep, pstreekönnte Folgendes aussehen:

bash(10102)───sleep(8506)

Beide haben Prozess-IDs (PIDs), auch wenn sie als Skript ausgeführt werden. Wenn wir den Schlaf unterbrechen wollten, würden wir senden kill 8506und die Bash-Sitzung würde fortgesetzt ... Das Problem liegt in einer Skriptumgebung vor, in der die PID des sleepBefehls nicht bekannt ist und kein Mensch den Prozess betrachten kann Baum.

Wir können die PID der Bash-Sitzung über die $$magische Variable erhalten. Wenn wir das irgendwo speichern kann, können wir dann gezielt Instanzen sleep, die ausgeführt werden unter der PID. Folgendes habe ich in das Skript eingefügt:

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

# go to sleep for a long time
sleep 1000

Und dann können wir sagen pkill, dass Nuke- sleepInstanzen unterhalb dieser PID ausgeführt werden:

pkill -P $(<myscript.pid) sleep

Dies beschränkt sich wiederum auf nur sleepProzesse, die direkt unter dieser einen Bash-Sitzung ausgeführt werden. Solange die PID korrekt protokolliert wurde, ist sie viel sicherer als killall sleepoder pkill sleep, was jeden sleep Prozess auf dem System gefährden könnte (erlaubte Berechtigungen).

Wir können diese Theorie mit dem folgenden Beispiel beweisen, in dem wir drei separate Bash-Sitzungen haben, zwei davon laufen sleep. Nur weil wir die PID der Bash-Sitzung oben links angeben, wird nur diese beendet sleep.

Bildbeschreibung hier eingeben


Ein alternativer Ansatz besteht darin, sleepin den Hintergrund zu treten, seine PID zu speichern und sie dann wieder in den Vordergrund zu stellen. Im Drehbuch:

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

Und um es zu töten:

kill $(<myscript.sleep.pid)
Oli
quelle
5

Sie können Ihr Skript schreiben, um andere Signale von kill usw. zu verarbeiten ("abzufangen"), damit Sie das Skriptverhalten nach Bedarf ändern können. Siehe man 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.
afbach
quelle
4

Sie könnten einfach den Schlaf beenden, was zur nächsten Zeile des Skripts führen würde:

pkill sleep

Beachten Sie, dass hierdurch alle in Ihrem System und nicht nur in Ihrem Skript ausgeführten Schlafvorgänge abgebrochen werden.

animaletdesequia
quelle
1

Ich habe ein schlafendes Bash-Skript, das von cronon boot gestartet wurde . Das Skript wird jede Minute aktiviert und stellt die Helligkeit der Laptop-Anzeige basierend auf Sonnenaufgang und Sonnenuntergang ein, die über das Internet abgerufen werden. Eine vom Benutzer konfigurierbare Übergangsphase zwischen Vollhelligkeit und Volldunkeligkeit erfordert das Erhöhen und Verringern der Werte um 3, 4, 5 oder was auch immer, die jede Minute berechnet werden.

Oli ging pstreein seiner Antwort kurz darauf ein, lehnte sie jedoch ab, da dies alle sleepInstanzen töten würde . Dies kann vermieden werden, indem die Suche mithilfe von pstree-Optionen eingegrenzt wird.

Unter Verwendung von sehen pstree -hwir die gesamte Hierarchie:

$ 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

Wie Sie sehen, enthält eine typische Ubuntu-Anmeldung viele viele PIDs (Prozess-IDs).

Wir können es auf unser laufendes Skript eingrenzen:

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

Wir sehen:

  • cron Shell gestartet (Prozess-ID 1308 und Sitzungs-ID 1308)
  • Die Shell ruft unser Programm auf, das unter der Prozess-ID 1321 und der Sitzungs-ID 1308 ausgeführt wird (passend zur Shell).
  • Unser Programm ruft sleepunter der Prozess-ID 26552 und erneut der Sitzungs-ID 1308 auf

An diesem Punkt können wir verwenden pkill -s 1308und es würde die gesamte Sitzung, die die Shell, unser Programm display-auto-brightnessund den sleepBefehl enthält, beenden . Stattdessen beenden wir kill 26552nur den Befehl sleep und zwingen unser Programm, aufzuwachen und die Helligkeit anzupassen.

Wenn Sie dies manuell in das angezeigte Terminal eingeben:

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

Der nächste Schritt ist, dies zu tun, wenn der Laptop aus dem Standby-Modus aufwacht. Beispielsweise war der geschlossene Deckel vollständig dunkel und die Bildschirmhelligkeit wurde auf "300" eingestellt. Wenn der Deckel geöffnet ist, ist Tageslicht und die Helligkeit muss auf "2000" eingestellt werden. Natürlich würde das Programm in 1 bis 59 Sekunden von selbst aufwachen, aber es ist bequemer, die Helligkeit sofort einzustellen.

Ich werde den Suspend / Resume-Code veröffentlichen, nachdem er geschrieben wurde. Hoffentlich dieses Wochenende.

WinEunuuchs2Unix
quelle