Comment continuer un script après avoir redémarré la machine?

18

J'écris un script shell en bash. À un moment donné du script, il détecte que la machine doit être redémarrée avant de continuer. Il délivre:

sudo reboot

Lorsque la machine revient, il y a plus de travail que ce script doit faire. Comment configurer quelque chose pour continuer à faire le travail dans ce script?

Je suppose qu'il y a un endroit où je peux écrire un script shell tel qu'il sera exécuté au prochain redémarrage. Où est un tel endroit? Je vois que cron a une directive @reboot. Je sais également que des services tels qu'Apache sont démarrés au démarrage par upstart. Est-ce que l'un ou l'autre de ces mécanismes serait approprié? Si oui, comment serait-il déclenché?

Ce script ne doit être exécuté qu'une seule fois, pas à chaque redémarrage. Il devra donc aller quelque part qui ne s'exécute qu'au prochain redémarrage, ou être capable de se supprimer une fois qu'il a été exécuté.

Cette question demande comment enregistrer l'état de votre application après le redémarrage. Mon script n'a pas beaucoup d'état, je peux donc gérer cela. J'ai juste besoin de savoir comment ce script peut déclencher quelque chose à exécuter après le prochain redémarrage.

Ma version spécifique est Ubuntu Linux 14.04. Le script d'origine est démarré sur la ligne de commande par un administrateur système (par opposition à l'exécution à partir de cron).

Stephen Ostermiller
la source
Un redémarrage dans un script ne doit être utilisé que si vous NE POUVEZ PAS l'éviter. Par exemple une nouvelle installation du noyau. Je suis sûr que vous pouvez faire votre travail sans redémarrer. Pouvez-vous spécifier pourquoi vous avez besoin du redémarrage?
chaos
1
Ce script installe un nouveau noyau (ou plutôt appelle apt upgrade qui peut le faire). Il vérifie également si un redémarrage est réellement nécessaire avant d'effectuer le redémarrage.
Stephen Ostermiller
"Un redémarrage dans un script ne doit être utilisé que si vous NE POUVEZ PAS l'éviter." - @chaos Pourquoi?
John Red

Réponses:

16

Sur un système, la seule chose qui est vraiment persistante est un fichier. C'est à peu près ce que vous devez utiliser. Voici une solution utilisant un script init.d.

Prenons le script (simple) suivant /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

Si vous l'activez avec update-rc.d myupdate defaults, l' startaction sera exécutée au démarrage. Maintenant, lorsque votre script de mise à jour appelle un redémarrage:

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

Avec cette solution, vous pouvez diviser votre script de mise à jour en deux parties:

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

Il exécutera la before_rebootsection de code, créera un fichier /var/runet redémarrera. Au démarrage, le script sera appelé à nouveau, mais puisque le fichier existe, after_rebootsera appelé à la place de before_reboot.

Notez que update-rc.dnécessite des privilèges root.

Sans utiliser de fichier (d' après le commentaire de Stephen Ostermiller ):

Si vous connaissez l' getoptsutilitaire, vous souhaiterez peut-être utiliser des options au lieu de fichiers. Dans le script init, appelez le script avec:

/path/to/update/script -r

Et dans votre script, vérifiez les options plutôt que les fichiers. Appelez votre script une fois sans l'option, et init.d le rappellera au démarrage, cette fois avec -r.

# Set AFTER_REBOOT according to options (-r).

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

Vous trouverez plus d'informations sur la gestion des options ici (pour les options courtes uniquement) . J'ai également édité mon script avec des appels à update-rc.dgarder ce travail ponctuel (à partir d'un autre commentaire).

John WH Smith
la source
2
Il pourrait être plus simple d'appeler à /path/to/update/script --after-rebootpartir /etc/init.d/myupdateplutôt que de compter sur la présence de /var/run/rebooting-for-updates. Ensuite, il aurait différents arguments lors de l'exécution directe vs appelé au démarrage.
Stephen Ostermiller
Sympa, je n'ai pas pensé aux options. Permettez-moi de modifier;)
John WH Smith
1
De plus, comme il s'agit d'un travail ponctuel, je voudrais probablement ajouter le update-rc.d myupdate defaultset update-rc.d myupdate removedans le script lui-même, ainsi que l'écriture et la suppression de /etc/init.d/myupdatesorte qu'il ne laisse pas de fichiers en suspens.
Stephen Ostermiller
J'ai implémenté cela et cela fonctionne bien. La seule autre chose que j'ajouterai est que mon système basé sur Debian nécessite des éléments supplémentaires dans la INIT INFOsection: wiki.debian.org/LSBInitScripts
Stephen Ostermiller
Je voulais vraiment rester simple;) Écrire un bon init.d prend un peu de temps, mais je suis content que vous soyez allé pour plus d'informations: ces scripts peuvent être assez pratiques.
John WH Smith