# Builds a " 3>&- 4>&-" string. # Note: one of these fds is a directory opened to /proc/self/fd # for globbing. It is unwanted, but I don't know how to filter it out. find_fds() { fds="" for f in /proc/self/fd/*; do test "$f" = "/proc/self/fd/0" && continue test "$f" = "/proc/self/fd/1" && continue test "$f" = "/proc/self/fd/2" && continue fds="$fds ${f##*/}>&-" done } find_fds fds1="$fds" # One of the fds is open to the script body # Close it while executing something. eval "find_fds $fds" # Shell should not lose that fd. Did it? find_fds test x"$fds1" = x"$fds" \ && { echo "Ok: script fd is not closed"; exit 0; } # One legit way to handle it is to move script fd. For example, if we see that fd 10 moved to fd 11: test x"$fds1" = x" 10>&- 3>&-" && \ test x"$fds" = x" 11>&- 3>&-" \ && { echo "Ok: script fd is not closed"; exit 0; } # or we see that fd 3 moved to fd 10: test x"$fds1" = x" 3>&- 4>&-" && \ test x"$fds" = x" 10>&- 3>&-" \ && { echo "Ok: script fd is not closed"; exit 0; } echo "Bug: script fd is closed" echo "fds1:$fds1" echo "fds2:$fds" exit 1