Shell Script – How to Continue a Script After Rebooting the Machine

rebootshell-script

I'm writing a shell script in bash. At some point in the script, it detects that the machine needs to be rebooted before continuing. It issues:

sudo reboot

When the machine comes back up, there is is more work that this script needs to do. How do I configure something to continue doing the work in this script?

I'm assuming that there is some place that I can write a shell script such that it will get executed at the next reboot. Where is such a place? I see that cron has an @reboot directive. I also know that services such as Apache are started on boot by upstart. Would either of those be appropriate mechanisms? If so, how would it be triggered?

This script only needs to run once, not every reboot. So it will have to go somewhere that just runs on the next reboot, or be able to remove itself once it has run.

This question asks about how to save your application state for after reboot. My script doesn't have much state, so I can manage that. I just need to know how to have this script trigger something to run after the next reboot.

My specific version is Ubuntu Linux 14.04. The original script is started on the command line by a system administrator (as opposed to running from cron).

Best Answer

On a system, the only thing that is really persistent is a file. That's pretty much what you should use. Here's an solution using an init.d script.

Let's consider the following (simple) script, /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

If you activate it with update-rc.d myupdate defaults, the start action will be executed upon boot. Now, when your update script calls for a reboot:

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

With this solution, you can divide your update script into two parts :

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

It'll execute the before_reboot code section, create a file in /var/run, and reboot. Upon boot, the script will be called again, but since the file exists, after_reboot will be called instead of before_reboot.

Note that update-rc.d requires root privileges.

Without using a file (from Stephen Ostermiller's comment):

If you are familiar with the getopts utility, you may want to use options instead of files. In the init script, call the script with:

/path/to/update/script -r

And in your script, check for options instead of files. Call your script once without the option, and init.d will call it again on boot, this time with -r.

# Set AFTER_REBOOT according to options (-r).

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

You'll find more information about option handling here (for short options only). I also edited my script with calls to update-rc.d to keep this a one-time job (from another comment).

Related Question