Best way to make a shell script daemon? Best way to make a shell script daemon? shell shell

Best way to make a shell script daemon?


Just backgrounding your script (./myscript &) will not daemonize it. See http://www.faqs.org/faqs/unix-faq/programmer/faq/, section 1.7, which describes what's necessary to become a daemon. You must disconnect it from the terminal so that SIGHUP does not kill it. You can take a shortcut to make a script appear to act like a daemon;

nohup ./myscript 0<&- &>/dev/null &

will do the job. Or, to capture both stderr and stdout to a file:

nohup ./myscript 0<&- &> my.admin.log.file &

Redirection explained (see bash redirection)

  • 0<&- closes stdin
  • &> file sends stdout and stderr to a file

However, there may be further important aspects that you need to consider. For example:

  • You will still have a file descriptor open to the script, which means that the directory it's mounted in would be unmountable. To be a true daemon you should chdir("/") (or cd / inside your script), and fork so that the parent exits, and thus the original descriptor is closed.
  • Perhaps run umask 0. You may not want to depend on the umask of the caller of the daemon.

For an example of a script that takes all of these aspects into account, see Mike S' answer.


Some of the top-upvoted answers here are missing some important parts of what makes a daemon a daemon, as opposed to just a background process, or a background process detached from a shell.

This http://www.faqs.org/faqs/unix-faq/programmer/faq/ describes what is necessary to be a daemon. And this Run bash script as daemon implements the setsid, though it misses the chdir to root.

The original poster's question was actually more specific than "How do I create a daemon process using bash?", but since the subject and answers discuss daemonizing shell scripts generally, I think it's important to point it out (for interlopers like me looking into the fine details of creating a daemon).

Here's my rendition of a shell script that would behave according to the FAQ. Set DEBUG to true to see pretty output (but it also exits immediately rather than looping endlessly):

#!/bin/bashDEBUG=false# This part is for fun, if you consider shell scripts fun- and I do.trap process_USR1 SIGUSR1process_USR1() {    echo 'Got signal USR1'    echo 'Did you notice that the signal was acted upon only after the sleep was done'    echo 'in the while loop? Interesting, yes? Yes.'    exit 0}# End of fun. Now on to the business end of things.print_debug() {    whatiam="$1"; tty="$2"    [[ "$tty" != "not a tty" ]] && {        echo "" >$tty        echo "$whatiam, PID $$" >$tty        ps -o pid,sess,pgid -p $$ >$tty        tty >$tty    }}me_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"me_FILE=$(basename $0)cd /#### CHILD HERE --------------------------------------------------------------------->if [ "$1" = "child" ] ; then   # 2. We are the child. We need to fork again.    shift; tty="$1"; shift    $DEBUG && print_debug "*** CHILD, NEW SESSION, NEW PGID" "$tty"    umask 0    $me_DIR/$me_FILE XXrefork_daemonXX "$tty" "$@" </dev/null >/dev/null 2>/dev/null &    $DEBUG && [[ "$tty" != "not a tty" ]] && echo "CHILD OUT" >$tty    exit 0fi##### ENTRY POINT HERE -------------------------------------------------------------->if [ "$1" != "XXrefork_daemonXX" ] ; then # 1. This is where the original call starts.    tty=$(tty)    $DEBUG && print_debug "*** PARENT" "$tty"    setsid $me_DIR/$me_FILE child "$tty" "$@" &    $DEBUG && [[ "$tty" != "not a tty" ]] && echo "PARENT OUT" >$tty    exit 0fi##### RUNS AFTER CHILD FORKS (actually, on Linux, clone()s. See strace -------------->                               # 3. We have been reforked. Go to work.exec >/tmp/outfileexec 2>/tmp/errfileexec 0</dev/nullshift; tty="$1"; shift$DEBUG && print_debug "*** DAEMON" "$tty"                               # The real stuff goes here. To exit, see fun (above)$DEBUG && [[ "$tty" != "not a tty" ]]  && echo NOT A REAL DAEMON. NOT RUNNING WHILE LOOP. >$tty$DEBUG || {while true; do    echo "Change this loop, so this silly no-op goes away." >/dev/null    echo "Do something useful with your life, young padawan." >/dev/null    sleep 10done}$DEBUG && [[ "$tty" != "not a tty" ]] && sleep 3 && echo "DAEMON OUT" >$ttyexit # This may never run. Why is it here then? It's pretty.     # Kind of like, "The End" at the end of a movie that you     # already know is over. It's always nice.

Output looks like this when DEBUG is set to true. Notice how the session and process group ID (SESS, PGID) numbers change:

<shell_prompt>$ bash blahd*** PARENT, PID 5180  PID  SESS  PGID 5180  1708  5180/dev/pts/6PARENT OUT<shell_prompt>$ *** CHILD, NEW SESSION, NEW PGID, PID 5188  PID  SESS  PGID 5188  5188  5188not a ttyCHILD OUT*** DAEMON, PID 5198  PID  SESS  PGID 5198  5188  5188not a ttyNOT A REAL DAEMON. NOT RUNNING WHILE LOOP.DAEMON OUT


# double background your script to have it detach from the tty# cf. http://www.linux-mag.com/id/5981 (./program.sh &) &