17

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).

  • A reboot within a script should only be used if you CANNOT avoid it. For example a new kernel installation. I'm sure you can do your job without reboot. Can you specify why you need the reboot? – chaos Jul 18 '14 at 13:27
  • 1
    This script installs a new kernel (or rather calls apt upgrade which may do so). It also checks too see whether a reboot is actually needed before doing the reboot. – Stephen Ostermiller Jul 18 '14 at 13:32
  • "A reboot within a script should only be used if you CANNOT avoid it." -- @chaos Why? – John Red Nov 16 '16 at 5:16
16

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).

  • 2
    It might be simpler to call /path/to/update/script --after-reboot from /etc/init.d/myupdate rather than relying on the presence of /var/run/rebooting-for-updates. Then it would have different arguments when run directly vs called at boot. – Stephen Ostermiller Jul 18 '14 at 13:50
  • Nice one, did not think about options. Allow me to edit ;) – John WH Smith Jul 18 '14 at 13:51
  • 1
    Also, since it is a one time job, I would probably want to add the update-rc.d myupdate defaults and update-rc.d myupdate remove into the script itself, as well as the writing and removal of /etc/init.d/myupdate so that it doesn't leave files sitting around. – Stephen Ostermiller Jul 18 '14 at 13:52
  • I've implemented this and it works well. The only other thing that I will add is that my Debian based system requires additional items in the INIT INFO section: wiki.debian.org/LSBInitScripts – Stephen Ostermiller Jul 19 '14 at 11:03
  • I really wanted to keep it simple ;) Writing proper init.d takes a little time, yet I'm glad you went for more information : these scripts can get pretty handy. – John WH Smith Jul 19 '14 at 13:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.