Bash Tip: Closing File Descriptors
I recently found that you can close bash file descriptors fairly easily, it goes like this:
exec 3>&- # close stdin
exec 2>&- # close stdout
exec 1>&- # 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 3>&- # close stdin
exec 2>&- # close stdout
exec 1>&- # 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).
Subscribe to the comments for this post
2 People have left comments on this post
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