¿Cómo continuar un script después de que reinicia la máquina?

18

Estoy escribiendo un script de shell en bash. En algún momento del script, detecta que la máquina necesita reiniciarse antes de continuar. Emite:

sudo reboot

Cuando la máquina vuelve a funcionar, hay más trabajo que este script necesita hacer. ¿Cómo configuro algo para continuar haciendo el trabajo en este script?

Supongo que hay un lugar donde puedo escribir un script de shell para que se ejecute en el próximo reinicio. ¿Dónde está ese lugar? Veo que cron tiene una directiva @reboot. También sé que los servicios como Apache se inician en el arranque por arranque. ¿Sería alguno de esos mecanismos apropiados? Si es así, ¿cómo se activaría?

Este script solo necesita ejecutarse una vez, no cada reinicio. Por lo tanto, tendrá que ir a algún lugar que solo se ejecute en el próximo reinicio, o podrá eliminarse una vez que se haya ejecutado.

Esta pregunta se refiere a cómo guardar el estado de su aplicación para después del reinicio. Mi script no tiene mucho estado, así que puedo manejarlo. Solo necesito saber cómo hacer que este script active algo para que se ejecute después del próximo reinicio.

Mi versión específica es Ubuntu Linux 14.04. El administrador del sistema inicia el script original en la línea de comandos (en lugar de ejecutarlo desde cron).

Stephen Ostermiller
fuente
Un reinicio dentro de un script solo debe usarse si NO PUEDE evitarlo. Por ejemplo, una nueva instalación de kernel. Estoy seguro de que puedes hacer tu trabajo sin reiniciar. ¿Puedes especificar por qué necesitas reiniciar?
caos
1
Este script instala un nuevo kernel (o más bien llama a apt upgrade que puede hacerlo). También comprueba si es necesario reiniciar antes de reiniciar.
Stephen Ostermiller
"Un reinicio dentro de un script solo debe usarse si NO PUEDE evitarlo". - @chaos ¿Por qué?
John Red

Respuestas:

16

En un sistema, lo único que es realmente persistente es un archivo. Eso es más o menos lo que debes usar. Aquí hay una solución usando un script init.d.

Consideremos el siguiente script (simple) /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 lo activa con update-rc.d myupdate defaults, la startacción se ejecutará al arrancar. Ahora, cuando su script de actualización requiere un reinicio:

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

Con esta solución, puede dividir su script de actualización en dos partes:

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

Ejecutará la before_rebootsección de código, creará un archivo /var/runy se reiniciará. Tras el arranque, el script se llama de nuevo, pero ya que el archivo existe, after_rebootse llama en lugar de before_reboot.

Tenga en cuenta que update-rc.drequiere privilegios de root.

Sin usar un archivo (del comentario de Stephen Ostermiller ):

Si está familiarizado con la getoptsutilidad, es posible que desee utilizar opciones en lugar de archivos. En el guión de inicio, llame al guión con:

/path/to/update/script -r

Y en su secuencia de comandos, busque opciones en lugar de archivos. Llame a su script una vez sin la opción, e init.d lo llamará nuevamente en el arranque, esta vez con -r.

# Set AFTER_REBOOT according to options (-r).

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

Encontrará más información sobre el manejo de opciones aquí (solo para opciones cortas) . También edité mi script con llamadas a update-rc.dpara mantener este trabajo por única vez (de otro comentario).

John WH Smith
fuente
2
Puede ser más simple llamar /path/to/update/script --after-rebootdesde en /etc/init.d/myupdatelugar de confiar en la presencia de /var/run/rebooting-for-updates. Entonces tendría diferentes argumentos cuando se ejecuta directamente frente a invocado en el arranque.
Stephen Ostermiller
Agradable, no pensé en las opciones. Permitirme editar;)
John WH Smith
1
Además, dado que es un trabajo de una sola vez, probablemente me gustaría agregar el update-rc.d myupdate defaultsy update-rc.d myupdate removeen el script en sí, así como la escritura y eliminación /etc/init.d/myupdatepara que no deje los archivos por ahí.
Stephen Ostermiller
He implementado esto y funciona bien. Lo único que agregaré es que mi sistema basado en Debian requiere elementos adicionales en la INIT INFOsección: wiki.debian.org/LSBInitScripts
Stephen Ostermiller
Realmente quería que fuera simple;) Escribir init.d apropiado lleva un poco de tiempo, pero me alegro de que hayas pedido más información: estos scripts pueden ser bastante útiles.
John WH Smith