Sign up ×
Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

I'd like to schedule a command to run after reboot on a Linux box. I know how to do this so the command consistently runs after every reboot with a @reboot crontab entry, however I only want the command to run once. After it runs, it should be removed from the queue of commands to run. I'm essentially looking for a Linux equivalent to RunOnce in the Windows world.

In case it matters:

$ uname -a
Linux devbox #1 SMP 2009-02-28 04:40:21 +0100 x86_64 x86_64 x86_64 GNU/Linux
$ bash --version
GNU bash, version 3.2.48(1)-release (x86_64-suse-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
$ cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)

Is there an easy, scriptable way to do this?

share|improve this question
RunOnce is an artifact of Windows resulting from problems completing configuration before a reboot. Is there any reason you can't run your script before reboot? The above solution appears to be a reasonable clone of RunOnce. – BillThor Jun 5 '10 at 0:49

7 Answers 7

Create an @reboot entry in your crontab to run a script called /usr/local/bin/runonce.

Create a directory structure called /etc/local/runonce.d/ran using mkdir -p.

Create the script /usr/local/bin/runonce as follows:

for file in /etc/local/runonce.d/*
    if [ ! -f "$file" ]
    mv "$file" "/etc/local/runonce.d/ran/$file.$(date +%Y%m%dT%H%M%S)"
    logger -t runonce -p "$file"

Now place any script you want run at the next reboot (once only) in the directory /etc/local/runonce.d and chown and chmod +x it appropriately. Once it's been run, you'll find it moved to the ran subdirectory and the date and time appended to its name. There will also be an entry in your syslog.

share|improve this answer
for file in /etc/local/runonce.d/*, no? – pra Jun 5 '10 at 5:00
@pra: Thanks for spotting that. – Dennis Williamson Jun 5 '10 at 5:25
Thanks for your answer. This solution is great. It technically solves my problem, however it seems like there's a lot of preparation of infrastructure required to make this work. It's not portable. I think your solution would ideally be baked into a Linux distribution (I'm not sure why it isn't!). Your answer inspired my ultimate solution, which I've also posted as an answer. Thanks again! – Christopher Parker Jun 9 '10 at 18:51
What made you choose local3, versus any of the other facilities between 0 and 7? – Christopher Parker Jun 10 '10 at 19:49
@Christopher: A dice roll is always the best method. Seriously, though, for an example it didn't matter and that's the key my finger landed on. Besides, I don't own any eight-sided die. – Dennis Williamson Jun 10 '10 at 20:19
up vote 15 down vote accepted

I really appreciate the effort put into Dennis Williamson's answer. I wanted to accept it as the answer to this question, as it is elegant and simple, however:

  • I ultimately felt that it required too many steps to set up.
  • It requires root access.

I think his solution would be great as an out-of-the-box feature of a Linux distribution.

That being said, I wrote my own script to accomplish more or less the same thing as Dennis's solution. It doesn't require any extra setup steps and it doesn't require root access.


if [[ $# -eq 0 ]]; then
    echo "Schedules a command to be run after the next reboot."
    echo "Usage: $(basename $0) <command>"
    echo "       $(basename $0) -p <path> <command>"
    echo "       $(basename $0) -r <command>"

    while getopts ":r:p:" optionName; do
        case "$optionName" in
            r) REMOVE=1; COMMAND=$OPTARG;;
            p) SCRIPTPATH=$OPTARG;;

    SCRIPT="${HOME}/.$(basename $0)_$(echo $COMMAND | sed 's/[^a-zA-Z0-9_]/_/g')"

    if [[ ! -f $SCRIPT ]]; then
        echo "PATH=$SCRIPTPATH" >> $SCRIPT
        echo "cd $(pwd)"        >> $SCRIPT
        echo "logger -t $(basename $0) -p \"COMMAND=$COMMAND ; USER=\$(whoami) ($(logname)) ; PWD=$(pwd) ; PATH=\$PATH\"" >> $SCRIPT
        echo "$COMMAND | logger -t $(basename $0) -p" >> $SCRIPT
        echo "$0 -r \"$(echo $COMMAND | sed 's/\"/\\\"/g')\""     >> $SCRIPT
        chmod +x $SCRIPT

    CRONTAB="${HOME}/.$(basename $0)_temp_crontab_$RANDOM"
    ENTRY="@reboot $SCRIPT"

    echo "$(crontab -l 2>/dev/null)" | grep -v "$ENTRY" | grep -v "^# DO NOT EDIT THIS FILE - edit the master and reinstall.$" | grep -v "^# ([^ ]* installed on [^)]*)$" | grep -v "^# (Cron version [^$]*\$[^$]*\$)$" > $CRONTAB

    if [[ $REMOVE -eq 0 ]]; then
        echo "$ENTRY" >> $CRONTAB

    crontab $CRONTAB
    rm $CRONTAB

    if [[ $REMOVE -ne 0 ]]; then
        rm $SCRIPT

Save this script (e.g.: runonce), chmod +x, and run:

$ runonce foo
$ runonce "echo \"I'm up. I swear I'll never email you again.\" | mail -s \"Server's Up\" $(whoami)"

In the event of a typo, you can remove a command from the runonce queue with the -r flag:

$ runonce fop
$ runonce -r fop
$ runonce foo

Using sudo works the way you'd expect it to work. Useful for starting a server just once after the next reboot.

myuser@myhost:/home/myuser$ sudo runonce foo
myuser@myhost:/home/myuser$ sudo crontab -l
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/root/.runonce_temp_crontab_10478 installed on Wed Jun  9 16:56:00 2010)
# (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $)
@reboot /root/.runonce_foo
myuser@myhost:/home/myuser$ sudo cat /root/.runonce_foo
cd /home/myuser
/home/myuser/bin/runonce -r "foo"

Some notes:

  • This script replicates the environment (PATH, working directory, user) it was invoked in.
  • It's designed to basically defer execution of a command as it would be executed "right here, right now" until after the next boot sequence.
share|improve this answer
Your script looks really handy. One thing to note is that it destructively strips comments out of the crontab. – Dennis Williamson Jun 9 '10 at 21:39
@Dennis: Thanks. I originally didn't have that extra grep call in there, but all of the comments were piling up; three for every time I ran the script. I think I'll change the script to just always remove comment lines that look like those three auto-generated comments. – Christopher Parker Jun 9 '10 at 21:47
@Dennis: Done. The patterns could probably be better, but it works for me. – Christopher Parker Jun 9 '10 at 22:02
@Dennis: Actually, based on crontab.c, I think my patterns are just fine. (Search for "DO NOT EDIT THIS FILE" at – Christopher Parker Jun 10 '10 at 23:24

Set up the script in /etc/rc5.d with an S99 and have it delete itself after running.

share|improve this answer

I think this answer is the most elegant:

Place script in /etc/init.d/script and self-delete with last line: rm $0

Unless the script is 100% fail-proof, probably wise to handle exceptions to avoid a fatal error loop..

share|improve this answer

in redhat and debian systems you can do that from /etc/rc.local, it's a kind of autoexec.bat.

share|improve this answer
That's going to get executed at each boot not just the next one only. – Dennis Williamson Jun 5 '10 at 22:46
my bad, I misread the question. Thanks for the correction – natxo asenjo Jun 6 '10 at 8:30

Create e.g. /root/


#your command here

sed -i '/' /etc/rc.local

Add to /etc/rc.local:


share|improve this answer

You can do this with the at command, although I notice you can't (at least on RHEL 5, which I tested on) use at @reboot or at reboot, but you can use at now + 2 minutes and then shutdown -r now.

This doesn't require that you system take longer than 2 minutes to run.

It may be useful where you want 0 set-up, although I do rather wish the 'runonce' command was standard kit.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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