Search code examples
raspberry-piraspbianshutdown

How do I run a Bash script before shutdown or reboot of a Raspberry Pi (running Raspbian)?


I want to run a Bash script prior to either shutdown or reboot of my Pi (running the latest Raspbian, a derivative of Debian).

e.g. if I type in sudo shutdown now or sudo reboot now into the command prompt, it should run my Bash script before continuing with shutdown/reboot.

I created a very simple script just for testing, to ensure I get the method working before I bother writing the actual script:

#!/bin/bash
touch /home/pi/ShutdownFileTest.txt

I then copied the file (called CreateFile.sh) to /etc/init.d/CreateFile I then created symlinks in /etc/rc0.d/ and /etc/rc6.d/:

sudo ln -s /etc/init.d/CreateFile K99Dave

I'm not certain on what the proper naming should be for the symlink. Some websites say "Start the filename with a K", some say "start with an S", one said: "start with K99 so it runs at the right time"...

I actually ended up trying all of the following (not all at once, of course, but one at a time):

sudo ln -s /etc/init.d/CreateFile S00Dave
sudo ln -s /etc/init.d/CreateFile S99Dave
sudo ln -s /etc/init.d/CreateFile K00Dave
sudo ln -s /etc/init.d/CreateFile K01rpa
sudo ln -s /etc/init.d/CreateFile K99Dave

After creating each symlink, I always ran:

sudo chmod a+x /etc/init.d/CreateFile && sudo chmod a+x /etc/rc6.d/<name of symlink>

I then rebooted each time.

Each time, the file at /home/pi/ShutdownFileTest.txt was not created; the script is not executed.

I found this comment on an older post, suggesting that the above was the outdated method:

The modern way to do this is via systemd. See "man systemd-shutdown" for details. Basically, put an executable shell script in /lib/systemd/system-shutdown/. It gets passed an argument like "halt" or "reboot" that allows you to distinguish the various cases if you need to.

I copied my script into /lib/systemd/system-shutdown/, chmod +x'd it, and rebooted, but still no success.

I note the above comment says that the script is passed "halt" or "reboot" as an argument. As it should run identically in both cases, I assume it shouldn't need to actually deal with that argument. I don't know how to deal with that argument, either, so I'm not sure if I need to do something to make that work or not...

Could someone please tell me where I'm going wrong?

Thanks in advance, Dave


Solution

  • As it turns out, part of the shutdown command has already executed (and unmounted the filesystem) before these scripts are executed.

    Therefore, mounting the filesystem at the start of the script and unmounting it at the end is necessary.

    Simply add:

    mount -oremount,rw /
    

    ...at the start of the script (beneath the #!/bin/bash)

    ...then have the script's code...

    and then finish the script with:

    mount -oremount,ro /
    

    So, the OP script should become:

    #!/bin/bash
    mount -oremount,rw /
    touch /home/pi/ShutdownFileTest.txt
    mount -oremount,ro /
    

    ...that then creates the file /home/pi/ShutdownFileTest.txt just before shutdown/reboot.


    That said, it may not be best practice to use this method. Instead, it is better to create a service that runs whenever the computer is on and running normally, but runs the desired script when the service is terminated (which happens at shutdown/reboot).

    This is explained in detail here, but essentially:

    1: Create a file (let's call it example.service).

    2: Add the following into example.service:

    [Unit]
    Description=This service calls shutdownScript.sh upon shutdown or reboot.
    
    [Service]
    Type=oneshot
    RemainAfterExit=true
    ExecStop=/home/pi/shutdownScript.sh
    
    [Install]
    WantedBy=multi-user.target
    

    3: Move it into the correct directory for systemd by running sudo mv /home/pi/example.service /etc/systemd/system/example.service

    4: Ensure the script to launch upon shutdown has appropriate permissions: chmod u+x /home/pi/shutdownScript.sh

    5: Start the service: sudo systemctl start example --now

    6: Make the service automatically start upon boot: sudo systemctl enable example

    7: Stop the service: sudo systemctl stop example

    This last command will mimic what would happen normally when the system shuts down, i.e. it will run /home/pi/shutdownScript.sh (without actually shutting down the system).

    You can then reboot twice and it should work from the second reboot onwards.

    EDIT: nope, no it doesn't. It worked the first time I tested it, but stopped working after that. Not sure why. If I figure out how to get it working, I'll edit this answer and remove this message (or if someone else knows, please feel free to edit the answer for me).