Alec the Geek

Reflections on software and related things from an older geek

  • Twitter Ramplings

  • My Bookmarks

  • RSS Alec’s GitHub

    • An error has occurred; the feed is probably down. Try again later.

Have a *nix sh script put itself into the background

Posted by Alec The Geek on 24 February 2011

In the Unix Bourne style shell languages (e.g. sh, bash, ksh etc) you can put a long running command (or another script) into the background so that control returns to the user. The original idea is that you can perform other work whilst the background process continues. This is achieved by adding a &, for example $ myVeryLongRunningCommand and options >/tmp/myOutput &.

It would be nice to be able to have scripts place themselves in the background, when appropriate, without the user having to worry about and I assumed there would be a “shell’ish” way to do that — however I couldn’t find anything so I knocked something up in a hurry. I put it here for future generations and in the hope that improvements will be suggested.

#! /bin/sh

if [[ "$_myBackGround" != "_backGroundFlag" ]]; then
 nohup /bin/sh -c "_myBackGround=_backGroundFlag; export _myBackGround;$0 $*" > /tmp/$0.$$.stdout 2> /tmp/$0.$$.stderr &
 echo $0 passed to background with arguments "$*". NB stderr is /tmp/$0.$$.stderr and stdout is /tmp/$0.$$.stdout
 exit
fi

#  Your script goes here e.g.

echo hello: My arguments are $0 $*

echo Hello -- this is an error >&2

About these ads

2 Responses to “Have a *nix sh script put itself into the background”

  1. Justin "Uni" Griggs said

    Hullo there sir, it’s about a year after you posted this and I stumbled upon it.

    I used your basic principle of the script being a self contained wrapper but improved upon it a bit to give it some more daemon-esque features, like a PID file and “safe” execution (i.e. if the script is already running the attempt to rerun it should throw an error, or in exceptional circumstances, try to correct itself.)

    For future generations, here is the code itself:

    http://pastebin.com/TkyJb50R WARNING: some of the language in the daemon section is a bit…colorful.

    The code relevant to the daemonization itself:

    #
    # Stage 4 Variables
    #
    # Required to identify this script from other instances
    ID=$$;
    # Location of the PID file.
    PID=/var/run/statusled.pid;
    # Easy reference to null device.
    NULL=/dev/null;
    # Processing string to seek out the statusled processes
    LOOKUP=$(ps aux | grep -e statusled.sh | grep -v ${ID}\
    | grep -v grep | awk ‘{print $2}’);

    #
    # Stage 4 Functions – Daemonize (Safely)
    #
    # First if loop checks if the file exists
    # Yes it does:
    # Second if loop checks if the PID is alive
    # Yes it is:
    # Exit with “I’m already Running.”
    # No it is not:
    # Third if loop checks if -A- statusled process is running
    # Yes there is:
    # The PID in the file is wrong, update it.
    # No there is not:
    # The process was killed, restart and write pid to file.
    # No it does not:
    # Second if loop checks if -A- statusled process is running
    # Yes there is:
    # Our PID file got deleted, recreate it.
    # No there is not:
    # Our Daemon was probably never started, start it.
    #
    # This is accomplished through a lot of nasty variable matching. The grep -o
    # line that follows the initial match line exists because for some reason bash
    # will fork this script into about 3 processes. We can find the first two, but
    # I was never able to use the special variables to pull up the third, so that
    # line uses this fork to our advantage, and scans the PID tree for any PIDs
    # that are also contained inside the PID file (from our first look up) and when
    # a match is found, it returns it. The basic principle depends on the kernel
    # not assigning us the same PID twice.
    #
    if [ -a /var/run/statusled.pid ]; then
    if ps -p $(cat ${PID}) > ${NULL}; then
    echo “StatusLED: I’m already running.”;
    else
    if ps -p ${LOOKUP} > ${NULL};
    then
    echo “StatusLED: I’m already running, but my PID number is wrong. Fixing…”
    echo ${LOOKUP} > ${PID};
    cat ${PID} | grep -o $(ps -p ${LOOKUP} | awk ‘{ print $1 }’\
    | sed ‘s/[^0-9]*//g’) > ${PID};
    else
    STATUS_LED &
    echo $! > ${PID}
    fi
    fi
    else
    if ps -p ${LOOKUP} > ${NULL};
    then
    echo “StatusLED: I’m already running, but my PID file is missing. Fixing…”
    echo ${LOOKUP} > ${PID};
    cat ${PID} | grep -o $(ps -p ${LOOKUP} | awk ‘{ print $1 }’\
    | sed ‘s/[^0-9]*//g’) > ${PID};
    else
    STATUS_LED &
    echo $! > ${PID};
    fi
    fi

    # EOF

Sorry, the comment form is closed at this time.

 
Follow

Get every new post delivered to your Inbox.

Join 272 other followers

%d bloggers like this: