Ich habe ein Shell-Skript, das regelmäßig über cron/crontab ausgeführt wird. Ich gebe dort sleep
fü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.log
scheint auf meinem System nicht aktualisiert zu werden)
Antwort1
Zunächst einmal ist zu beachten, dass sleep
die 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, sleep
wird 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 5m
Befehl 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_MONOTONIC
wird 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_REALTIME
die 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 systemd
das Journalsystem verfügbar sein, etwa mit:
journalctl -r | awk '/resume/ {print $0; exit}'
Daher können Sie den Zeitstempel im short-iso
Format 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 (bash
spezifische 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.