Bash Tip: Closing File Descriptors

Gravatar

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).


Posted on : Oct 24 2007
Posted under Software Development, cli, linux |

2 People have left comments on this post

Apr 18, 2008 - 10:04:00
Gravatar  dandu said:

hey, stdin is on fd 0 not 3 :)

Oct 15, 2008 - 08:10:17
Gravatar  ndronen said:

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