Bash – Testing if a file descriptor is valid

bashfile-descriptors

I'd like to make a bash script output additional information to file descriptors (FDs) greater than or equal to 3, when they are open. To test whether an FD is open, I devised the following trick:

if (printf '' 1>&3) 2>&-; then
  # File descriptor 3 is open
else
  # File descriptor 3 is not open
fi

This is sufficient for my needs, but I'm curious as to whether there is a more idiomatic way of testing if an FD is valid. I'm especially interested about whether there exists a mapping of the fcntl(1) syscall to a shell command, which would allow the retrieval of FD flags (O_WRONLY and O_RDWR to test whether the FD is writable, and O_RDONLY and O_RDWR to test whether the FD is readable).

Best Answer

In ksh (both AT&T and pdksh variants) or zsh, you can do:

if print -nu3; then
  echo fd 3 is writeable
fi

They won't write anything on that fd, but still check if the fd is writable (using fcntl(3, F_GETFL)) and report an error otherwise:

$ ksh -c 'print -nu3' 3< /dev/null
ksh: print: -u: 3: fd not open for writing

(which you can redirect to /dev/null).

With bash, I think your only option is to check if a dup() succeeds like in your approach, though that won't guarantee that the fd is writable (or call an external utility (zsh/perl...) to do the fcntl()).

Note that in bash (like most shells), if you use (...) instead of {...;}, that will fork an extra process. You can use:

if { true >&3; } 2<> /dev/null

instead to avoid the fork (except in the Bourne shell where redirecting compound commands always causes a subshell). Don't use : instead of true as that's a special builtin, so would cause the shell to exit when bash is in POSIX compliance mode.

You could however shorten it to:

if { >&3; } 2<> /dev/null