How to find next available file descriptor in Bash?

If you do not care if the file descriptor is above 9, you may ask the shell itself to provide one. Of course, the fd is guaranteed to be free by the own shell.

Feature available since bash 4.1+ (2009-12-31) {varname} style automatic file descriptor allocation

$ exec {var}>hellofile
$ echo "$var"
15

$ echo "this is a test" >&${var}
$ cat hellofile
this is a test

$ exec {var}>&-                      # to close the fd.

In fact, in linux, you can see the open fds with:

$ ls /proc/$$/fd
0 1 2 255

In pure bash, you can use the following method to see if a given file descriptor (3 in this case) is available:

rco="$(true 2>/dev/null >&3; echo $?)"
rci="$(true 2>/dev/null <&3; echo $?)"
if [[ "${rco}${rci}" = "11" ]] ; then
    echo "Cannot read or write fd 3, hence okay to use"
fi

This basically works by testing whether you can read or write to the given file handle. Assuming you can do neither, it's probably okay to use.

In terms of finding the first free descriptor, you can use something like:

exec 3>/dev/null    # Testing, comment out to make
exec 4</dev/null    # descriptor available.

found=none
for fd in {0..200}; do
    rco="$(true 2>/dev/null >&${fd}; echo $?)"
    rci="$(true 2>/dev/null <&${fd}; echo $?)"
    [[ "${rco}${rci}" = "11" ]] && found=${fd} && break
done
echo "First free is ${found}"

Running that script gives 5 as the first free descriptor but you can play around with the exec lines to see how making an earlier one available will allow the code snippet to find it.


As pointed out in the comments, systems that provide procfs (the /proc file system) have another way in which they can detect free descriptors. The /proc/PID/fd directory will contain an entry for each open file descriptor as follows:

pax> ls -1 /proc/$$/fd
0
1
2
255

So you could use a script similar to the one above to find a free entry in there:

exec 3>/dev/null    # Testing, comment out to make
exec 4</dev/null    #   descriptor available.

found=none
for fd in {0..200} ; do
    [[ ! -e /proc/$$/fd/${fd} ]] && found=${fd} && break
done
echo "First free is ${found}"

Just keep in mind that not all systems providing bash will necessarily have procfs (the BDSs and CygWin being examples). Should be fine for Linux if that's the OS you're targeting.


Of course, you do still have the option of wrapping your entire shell script as something like:

(
    # Your current script goes here
)

In that case, the file handles will be preserved outside those parentheses and you can manipulate them within as you see fit.


The other answer that uses pre-bash-4.1 syntax does a lot unnecessary subshell spawning and redundant checks. It also has an arbitrary cut-off for the maximum FD number.

The following code should do the trick with no subshell spawning (other than for a ulimit call if we want to get a decent upper limit on FD numbers).

fd=2 max=$(ulimit -n) &&
while ((++fd < max)); do
   ! <&$fd && break
done 2>/dev/null &&
echo $fd
  • Basically we just iterate over possible FDs until we reach one we can't dupe.
  • In order to avoid the Bad file descriptor error message from the last loop iteration, we redirect stderr for the whole while loop.