I recently found that you can close bash file descriptors fairly easily, it goes like this:
exec 0>&- # close stdin exec 1>&- # close stdout exec 2>&- # close stderr
Which makes it easy to daemonize things using only bash (lets face it there are times when you JUST don’t need anything more than a simple bash script, you just need it backgrounded/daemonized). Take this example of a daemon that copies any new files created in a directory to another place on the filesystem
#!/bin/bash ## ## Shell Daemon For: Backup /root/ ## (poorly coded, quick and dirty, example) ## PIDFILE="/var/run/rootmirror.pid" LOGFILE="/log/log/rootmirror-%Y-%m-%d.log" NOHUP="/usr/bin/nohup" CRONOLOG="/usr/bin/cronolog" case $1 in start) exec 0>&- # close stdin exec 1>&- # close stdout exec 2>&- # close stderr $NOHUP $0 run | $CRONOLOG $LOGFILE >> /dev/null & ;; stop) /bin/kill $(cat $PIDFILE) ;; run) pgrep -f "$0 $1" > $PIDFILE while [ true ]; do event=$(inotifywait -q -e close_write --format "%f" /root/) ( cp -v "/root/$event" "/var/lib/rootmirror/$event" )& done ;; *) echo "$0 [ start | stop ]" exit 0 ;; esac
One especially nice detail here is that this wont hang while exiting your SSH session after you start it up (a big pet peeve of mine).
hey, stdin is on fd 0 not 3 🙂
Yeah, this is broken:
exec 3>&- # close stdin
exec 2>&- # close stdout
exec 1>&- # close stderr
It should be
exec 0>&- # close stdin
exec 1>&- # close stdout
exec 2>&- # close stderr
why not just start up screen and while true;do sh myscript.sh; done ?
then attach to the screen session if you ever want to close it. Then you don't ever have to worry about the PID getting recycled, and your script accidentally closing the wrong process!
@foo Granted. But sometimes screen is not necessary or wanted. checking the PIDfile contents versus the running process list is, naturally, a good idea. But the post was about closing the file descriptors, not writing idfiles or killing processes, so the example is just that: an example.
You posted this quite some time ago but i have a little improvment for you: use $$ in bashto get the current process id, not pgrep. Otherwise, interesting example.
Greets,
Dennis
Should closing stdio be:
exec 0<&- # close stdin
instead?
You should be redirecting stdin, stdout, and stderr to /dev/null……. instead of just closing them.
And one more comment on an old thread… Bash has a wonderful built-in called "disown" that fully disconnects from a process. You can do do something like this:
program &
disown %1
This completely disconnects it from all open channels and makes it very easy to launch and forget.