Wie kann man in einem Shell-Skript erkennen, ob dieses Skript nach dem Anhalten fortgesetzt wird?

Wie kann man in einem Shell-Skript erkennen, ob dieses Skript nach dem Anhalten fortgesetzt wird?

Ich habe ein Shell-Skript, das regelmäßig über cron/crontab ausgeführt wird. Ich gebe dort sleepfür einige Minuten einen Befehl ein:

sleep 5m # Waits 5 minutes.

Dies ist notwendig, da die nachfolgenden Aktionen von einem konsistenten Zustand der Dateien abhängen, die von anderen (unabhängigen) Prozessen synchronisiert werden müssen.

Wenn mein Computer aus dem Ruhezustand/Suspendierungsmodus zurückkommt, möchte ich nicht mit der Ausführung des Skripts fortfahren (da der Computer möglicherweise erst nach 4 Minuten und 59 Sekunden aufwacht, sodass die Dateien noch nicht synchronisiert sind).

Wie kann ich in einem Shell-Skript überprüfen, ob das Aufwachen aus dem Ruhezustand länger als 5 Minuten her ist?

(das Datum /var/log/pm-suspend.logscheint auf meinem System nicht aktualisiert zu werden)

Antwort1

Zunächst einmal ist zu beachten, dass sleepdie Sperrzeit dabei nicht berücksichtigt wird.

Wenn Sie beispielsweise den Befehl ausführen sleep 5m, den Computer dann in den Ruhezustand versetzen und ihn 4 Minuten später wieder aktivieren, sleepwird der Befehl 9 Minuten nach dem Start beendet. Er verharrt 5 Minuten lang im Ruhezustand.

Vor diesem Hintergrund glaube ich nicht, dass Sie den Hack, den Sie suchen, überhaupt brauchen. Ihre Frage implizierte die entgegengesetzte, falsche Annahme, nämlich dass ein sleep 5mBefehl 4 Minuten und 59 Sekunden, die der Computer im Ruhezustand verbrachte, und 1 Sekunde Wachzeit durchschlafen kann.


Vor diesem Hintergrund wollen wir uns nun eine Möglichkeit ansehen, mit der man feststellen kann, ob der Computer zwischen zwei Zeitpunkten angehalten wurde.

Es gibt einige Systemuhren, wie im clock_gettime(2)Handbuch beschrieben.

Erstens CLOCK_MONOTONICwird die Unterbrechungszeit nicht mitgezählt. Es handelt sich um einen Wert in Sekunden, der von einem beliebigen Startpunkt ausgeht und die Zeit angibt, die der Computer tatsächlich wach war.

Es gibt noch eine andere, CLOCK_REALTIMEdie die reale Zeit angibt. Allerdings ist sie anfällig für plötzliche Sprünge, wenn die Uhr verstellt wird, und daher nicht ganz zuverlässig. Verwenden wir stattdessen CLOCK_BOOTTIME. Dies ist ein Wert in Sekunden, ausgehend von einem beliebigen Startpunkt (vermutlich der Startzeit des Systems), einschließlich der Zeit, die der Computer im Ruhezustand verbracht hat.

Sie können diese beiden Werte mit Befehlen wie

python3 -c 'import time; print(time.clock_gettime(time.CLOCK_MONOTONIC))'
python3 -c 'import time; print(time.clock_gettime(time.CLOCK_BOOTTIME))'

(Es gibt auch eine einfachere Syntax, um die monotone Zeit zu erhalten. Ich habe bewusst die Syntax gewählt, die für beide Arten von Uhren funktioniert.)

Fragen Sie an einem bestimmten Punkt diese beiden Werte ab und berechnen Sie deren Differenz. Wiederholen Sie diesen Vorgang an einem anderen Punkt.

Die Differenz dieser beiden Werte gibt die Zeitspanne an, in der der Computer zwischendurch angehalten hat. Gegebenenfalls ist ein kleiner Messfehler möglich, da die beiden Werte nicht im selben Moment abgefragt werden können.

Antwort2

Ein Weg

Der letzte Wiederaufnahmezeitpunkt sollte über systemddas Journalsystem verfügbar sein, etwa mit:

journalctl -r | awk '/resume/ {print $0; exit}'

Daher können Sie den Zeitstempel im short-isoFormat einer Variablen mit etwa folgendem Format zuweisen:

lr="$(journalctl -r -o short-iso | awk '/resume/ {printf "%s", $1; exit}')"

und fügen Sie fünf Minuten hinzu, während Sie es in einen Unix-Zeitstempel konvertieren, etwa mit:

lr5="$(date -d "$lr + 5 minutes" +'%s')"

und vergleichen/bewerten Sie den späteren mit dem aktuellen Unix-Zeitstempel mit etwas wie (bashspezifische Syntax):

if [[ "$(date +'%s')" -ge "$lr5" ]]
  then
    echo "Five minutes have passed since last resume."
    # Your command/s here
    fi

Ein anderer Weg

Sie können Ihren eigenen Zeitstempel erstellen, indem Sie mithilfe dieser Vorlage eine Skriptdatei im /lib/systemd/system-sleep/Verzeichnis platzieren:

#!/bin/sh

case "${1}" in
  pre)
    # Command(s)/script(s) to execute before system goes to sleep/hibernate
    # nothing
      ;;
  post)
    # Command(s)/script(s) to execute after system wakes up from sleep/hibernate
    # Save your timestamp e.g.:
    # /bin/date +'%s' > /home/user/timestamp.log
      ;;
esac

Und verwenden Sie eine ähnliche Logik wie bei der ersten Methode zum Parsen und Auswerten basierend auf dem Zeitstempel aus Ihrer eigenen benutzerdefinierten Protokolldatei.

Beachten: Informationen zur Verwendung der zweiten Möglichkeit zum Ausführen von Skripten, die eine Netzwerkverbindung benötigen/auf diese angewiesen sind, finden Sie zunächst unter:Der netzwerkbezogene Teil eines Skripts wird in /lib/systemd/system-sleep nicht ausgeführt.

verwandte Informationen