Best way to make a shell script a daemon?

I am wondering if there is a better way to make a daemon that is waiting for something using only sh than:

#! /bin/sh trap processUserSig SIGUSR1 processUserSig() { echo "doing stuff" } while true; do sleep 1000 done 

In particular, I am wondering if there is a way to get rid of the cycle and still listen to music.

+56
bash shell
Aug 07 2018-10-12T00:
source share
9 answers

Use a system daemon tool, such as start-stop-daemon .

Otherwise, yes, there must be a loop somewhere.

+35
Aug 07 '10 at 14:09
source share
β€” -

A simple description of the script ( ./myscript & ) will not lead to its demonization. See http://www.faqs.org/faqs/unix-faq/programmer/faq/ , section 1.7, which describes what it takes to become a demon. You must disconnect it from the terminal so that SIGHUP does not kill it. You can make a shortcut to make the script appear as a daemon,

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

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

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

However, there may be other important aspects to consider. For example:

  • You will still have a file descriptor open for the script, which means that the directory in which it was installed would be unmounted. To be a true daemon, you must chdir("/") (or cd / inside your script) and fork in order for the parent to exit, and therefore the original handle is closed.
  • Maybe run umask 0 . You may not want to depend on the umask of the daemon's caller.

For an example script that takes all these aspects into account, see Mike C.'s answer .

+95
Jun 06 '12 at 4:50
source share
 # double background your script to have it detach from the tty # cf. http://www.linux-mag.com/id/5981 (./program.sh &) & 
+54
Aug 07 '10 at 15:34
source share

Some of the answers above do not include some important parts of what makes a daemon a demon, not just a background process, or a background process separate from the shell.

This http://www.faqs.org/faqs/unix-faq/programmer/faq/ describes what it takes to be a demon. And this Run bash script as a daemon implements setid, although it skips chdir for root.

The original question with the poster was more specific than β€œHow to create a daemon process using bash?”, But since the topic and answers discuss demounting shell scripts in general, I think it’s important to indicate this (for intruders, I look at the small details of creating a daemon )

Here's my execution of a shell script that will behave according to the FAQ. Set DEBUG to true to see a pretty output (but it also crashes quickly, and not cyclically):

 #!/bin/bash DEBUG=false # This part is for fun, if you consider shell scripts fun- and I do. trap process_USR1 SIGUSR1 process_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 0 fi ##### 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 0 fi ##### RUNS AFTER CHILD FORKS (actually, on Linux, clone()s. See strace --------------> # 3. We have been reforked. Go to work. exec >/tmp/outfile exec 2>/tmp/errfile exec 0</dev/null shift; 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 man." >/dev/null sleep 10 done } $DEBUG && [[ "$tty" != "not a tty" ]] && sleep 3 && echo "DAEMON OUT" >$tty exit # This may never run. Why is it here then? It pretty. # Kind of like, "The End" at the end of a movie that you # already know is over. It always nice. 

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

 <shell_prompt>$ bash blahd *** PARENT, PID 5180 PID SESS PGID 5180 1708 5180 /dev/pts/6 PARENT OUT <shell_prompt>$ *** CHILD, NEW SESSION, NEW PGID, PID 5188 PID SESS PGID 5188 5188 5188 not a tty CHILD OUT *** DAEMON, PID 5198 PID SESS PGID 5198 5188 5188 not a tty NOT A REAL DAEMON. NOT RUNNING WHILE LOOP. DAEMON OUT 
+52
Mar 17 '15 at 19:08
source share

It really depends on what the binary itself will do.

For example, I want to create several listeners.

Starting Daemon is a simple task:

lis_deamon:

 #!/bin/bash # We will start the listener as Deamon process # LISTENER_BIN=/tmp/deamon_test/listener test -x $LISTENER_BIN || exit 5 PIDFILE=/tmp/deamon_test/listener.pid case "$1" in start) echo -n "Starting Listener Deamon .... " startproc -f -p $PIDFILE $LISTENER_BIN echo "running" ;; *) echo "Usage: $0 start" exit 1 ;; esac 

this is how we run the daemon (a common way for all /etc/init.d/)

Now, as for the listener, himself, It should be some kind of cycle / notification or otherwise, which will cause the script to do what you want. For example, if you want your script to sleep 10 minutes and wake up and ask how you do it, do it with

 while true ; do sleep 600 ; echo "How are u ? " ; done 

Here is a simple listener that you can do that will listen to your commands from a remote computer and execute them on the local computer:

listener:

 #!/bin/bash # Starting listener on some port # we will run it as deamon and we will send commands to it. # IP=$(hostname --ip-address) PORT=1024 FILE=/tmp/backpipe count=0 while [ -a $FILE ] ; do #If file exis I assume that it used by other program FILE=$FILE.$count count=$(($count + 1)) done # Now we know that such file do not exist, # U can write down in deamon it self the remove for those files # or in different part of program mknod $FILE p while true ; do netcat -l -s $IP -p $PORT < $FILE |/bin/bash > $FILE done rm $FILE 

So, to run UP: / tmp / deamon_test / startener start

and send commands from the shell (or wrap it in a script):

 test_host#netcat 10.184.200.22 1024 uptime 20:01pm up 21 days 5:10, 44 users, load average: 0.62, 0.61, 0.60 date Tue Jan 28 20:02:00 IST 2014 punt! (Cntrl+C) 

Hope this helps.

+4
Jan 28 '14 at 18:17
source share

Check out the daemon tool from the libslack package:

http://ingvar.blog.linpro.no/2009/05/18/todays-sysadmin-tip-using-libslack-daemon-to-daemonize-a-script/

On Mac OS X, use a script to run the shell.

+1
Aug 07 2018-10-14T00:
source share

If I had script.sh and I wanted to execute it from bash and leave it running even when I want to close the bash session, then I would combine nohup and & at the end.

Example: nohup ./script.sh < inputFile.txt > ./logFile 2>&1 &

inputFile.txt can be any file. If your file has no input, we usually use /dev/null . Thus, the command will:

nohup ./script.sh < /dev/null > ./logFile 2>&1 &

After that, close the bash session, open another terminal and run: ps -aux | egrep "script.sh" ps -aux | egrep "script.sh" and you will see that your script is still running in the background. Of course, if you want to stop it, run the same command (ps) and kill -9 <PID-OF-YOUR-SCRIPT>

+1
01 Oct '15 at 19:43
source share

See the Bash Service Manager project: https://github.com/reduardo7/bash-service-manager

Implementation example

 #!/usr/bin/env bash export PID_FILE_PATH="/tmp/my-service.pid" export LOG_FILE_PATH="/tmp/my-service.log" export LOG_ERROR_FILE_PATH="/tmp/my-service.error.log" . ./services.sh run-script() { local action="$1" # Action while true; do echo "@@@ Running action '${action}'" echo foo echo bar >&2 [ "$action" = "run" ] && return 0 sleep 5 [ "$action" = "debug" ] && exit 25 done } before-start() { local action="$1" # Action echo "* Starting with $action" } after-finish() { local action="$1" # Action local serviceExitCode=$2 # Service exit code echo "* Finish with $action. Exit code: $serviceExitCode" } action="$1" serviceName="Example Service" serviceMenu "$action" "$serviceName" run-script "$workDir" before-start after-finish 

Usage example

 $ ./example-service # Actions: [start|stop|restart|status|run|debug|tail(-[log|error])] $ ./example-service start # Starting Example Service service... $ ./example-service status # Serive Example Service is runnig with PID 5599 $ ./example-service stop # Stopping Example Service... $ ./example-service status # Service Example Service is not running 
0
Jun 03 '17 at 1:22
source share

try executing with & if you save this file as program.sh

you can use

 $. program.sh & 
-one
Aug 07 '10 at 14:15
source share



All Articles