Wie setze ich ein Skript nach dem Neustart des Computers fort?

18

Ich schreibe ein Shell-Skript in Bash. Irgendwann im Skript wird festgestellt, dass der Computer neu gestartet werden muss, bevor der Vorgang fortgesetzt werden kann. Es gibt heraus:

sudo reboot

Wenn der Computer wieder hochfährt, muss dieses Skript noch mehr Arbeit erledigen. Wie konfiguriere ich etwas, um die Arbeit in diesem Skript fortzusetzen?

Ich gehe davon aus, dass ich irgendwo ein Shell-Skript schreiben kann, das beim nächsten Neustart ausgeführt wird. Wo ist so ein Ort? Ich sehe, dass Cron eine @ Reboot-Direktive hat. Ich weiß auch, dass Dienste wie Apache beim Booten von upstart gestartet werden. Wäre einer dieser Mechanismen angemessen? Wenn ja, wie würde es ausgelöst?

Dieses Skript muss nur einmal ausgeführt werden, nicht bei jedem Neustart. Es muss also irgendwohin gehen, wo es nur beim nächsten Neustart ausgeführt wird, oder es muss sich selbst entfernen können, sobald es ausgeführt wurde.

Bei dieser Frage wird gefragt, wie der Anwendungsstatus nach dem Neustart gespeichert werden soll. Mein Skript hat nicht viel Status, also kann ich das verwalten. Ich muss nur wissen, wie dieses Skript etwas auslöst, das nach dem nächsten Neustart ausgeführt wird.

Meine spezielle Version ist Ubuntu Linux 14.04. Das ursprüngliche Skript wird in der Befehlszeile von einem Systemadministrator gestartet (im Gegensatz zum Ausführen von Cron).

Stephen Ostermiller
quelle
Ein Neustart innerhalb eines Skripts sollte nur verwendet werden, wenn Sie ihn NICHT vermeiden können. Zum Beispiel eine neue Kernel-Installation. Ich bin sicher, Sie können Ihre Arbeit erledigen, ohne einen Neustart durchführen zu müssen. Können Sie angeben, warum Sie den Neustart benötigen?
Chaos
1
Dieses Skript installiert einen neuen Kernel (oder ruft apt upgrade auf, wenn dies möglich ist). Außerdem wird überprüft, ob tatsächlich ein Neustart erforderlich ist, bevor der Neustart durchgeführt wird.
Stephen Ostermiller
"Ein Neustart innerhalb eines Skripts sollte nur verwendet werden, wenn Sie ihn NICHT vermeiden können." - @chaos Warum?
John Red

Antworten:

16

Auf einem System ist das einzige, was wirklich dauerhaft ist, eine Datei. Das ist so ziemlich das, was Sie verwenden sollten. Hier ist eine Lösung mit einem init.d-Skript.

Betrachten wir das folgende (einfache) Skript /etc/init.d/myupdate:

#! /bin/sh

### BEGIN INIT INFO
# Provides:          myupdate
### END INIT INFO

PATH=/sbin:/bin:/usr/sbin:/usr/bin

case "$1" in
    start)
        /path/to/update/script
        ;;
    stop|restart|reload)
        ;;
esac

Wenn Sie es mit aktivieren update-rc.d myupdate defaults, wird die startAktion beim Booten ausgeführt. Wenn Ihr Update-Skript jetzt einen Neustart erfordert:

touch /var/run/rebooting-for-updates
sudo reboot

Mit dieser Lösung können Sie Ihr Update-Skript in zwei Teile teilen:

before_reboot(){
    # Do stuff
}

after_reboot(){
    # Do stuff
}

if [ -f /var/run/rebooting-for-updates ]; then
    after_reboot
    rm /var/run/rebooting-for-updates
    update-rc.d myupdate remove
else
    before_reboot
    touch /var/run/rebooting-for-updates
    update-rc.d myupdate defaults
    sudo reboot
fi

Es wird den before_rebootCode-Abschnitt ausführen , eine Datei erstellen /var/runund neu starten. Beim Booten wird das Skript erneut aufgerufen, aber da die Datei vorhanden ist, after_rebootwird statt aufgerufen before_reboot.

Beachten Sie, update-rc.ddass Root-Rechte erforderlich sind.

Ohne Verwendung einer Datei (aus Stephen Ostermillers Kommentar):

Wenn Sie mit dem getoptsDienstprogramm vertraut sind , möchten Sie möglicherweise Optionen anstelle von Dateien verwenden. Rufen Sie im Init-Skript das Skript auf mit:

/path/to/update/script -r

Suchen Sie in Ihrem Skript nach Optionen anstelle von Dateien. Rufen Sie Ihr Skript einmal ohne die Option auf, und init.d ruft es beim Booten erneut auf, diesmal mit -r.

# Set AFTER_REBOOT according to options (-r).

if [ "x$AFTER_REBOOT" = "xyes" ]; then
    # After reboot
else
    # Before reboot
fi

Weitere Informationen zum Umgang mit Optionen finden Sie hier (nur für kurze Optionen) . Ich habe auch mein Skript mit Aufrufen bearbeitet update-rc.d, um dies als einmaligen Auftrag zu behalten (aus einem anderen Kommentar).

John WH Smith
quelle
2
Es könnte einfacher sein , zu nennen /path/to/update/script --after-rebootaus und /etc/init.d/myupdatenicht auf dem Vorhandensein von Berufung /var/run/rebooting-for-updates. Dann hätte es verschiedene Argumente, wenn es direkt ausgeführt und beim Booten aufgerufen würde.
Stephen Ostermiller
Schön, habe nicht über Optionen nachgedacht. Erlauben Sie mir, zu bearbeiten;)
John WH Smith
1
Da es sich um eine einmalige Aufgabe handelt, möchte ich wahrscheinlich das update-rc.d myupdate defaultsund update-rc.d myupdate removein das Skript selbst einfügen sowie das Schreiben und Entfernen von /etc/init.d/myupdateDateien, damit keine Dateien herumliegen.
Stephen Ostermiller
Ich habe dies implementiert und es funktioniert gut. Die einzige andere Sache, die ich hinzufügen werde, ist, dass mein Debian-basiertes System zusätzliche Elemente in dem INIT INFOAbschnitt benötigt: wiki.debian.org/LSBInitScripts
Stephen Ostermiller
Ich wollte es wirklich einfach halten;) Das Schreiben von "proper init.d" nimmt etwas Zeit in Anspruch, aber ich bin froh, dass Sie weitere Informationen gesucht haben: Diese Skripte können sehr nützlich sein.
John WH Smith