There are two reasons lsof | wc -l
doesn't count file descriptors. One is that it lists things that aren't open files, such as loaded dynamically linked libraries and current working directories; you need to filter them out. Another is that lsof
takes some time to run, so can miss files that are opened or closed while it's running; therefore the number of listed open files is approximate. Looking at /proc/sys/fs/file-nr
gives you an exact value at a particular point in time.
cat /proc/sys/fs/file-nr
is only useful when you need the exact figure, mainly to check for resource exhaustion. If you want to list the open files, you need to call lsof
, or use some equivalent method such as trawling /proc/*/fd
manually.
To answer literally, to close all open file descriptors for bash
:
for fd in $(ls /proc/$$/fd); do
eval "exec $fd>&-"
done
However this really isn't a good idea since it will close the basic file descriptors the shell needs for input and output. If you do this, none of the programs you run will have their output displayed on the terminal (unless they write to the tty
device directly). If fact in my tests closing stdin
(exec 0>&-
) just causes an interactive shell to exit.
What you may actually be looking to do is rather to close all file descriptors that are not part of the shell's basic operation. These are 0 for stdin
, 1 for stdout
and 2 for stderr
. On top of this some shells also seem to have other file descriptors open by default. In bash
, for example, you have 255 (also for terminal I/O) and in dash
I have 10, which points to /dev/tty
rather than the specific tty
/pts
device the terminal is using. To close everything apart from 0, 1, 2 and 255 in bash
:
for fd in $(ls /proc/$$/fd); do
case "$fd" in
0|1|2|255)
;;
*)
eval "exec $fd>&-"
;;
esac
done
Note also that eval
is required when redirecting the file descriptor contained in a variable, if not bash
will expand the variable but consider it part of the command (in this case it would try to exec
the command 0
or 1
or whichever file descriptor you are trying to close).
NOTE: Also using a glob instead of ls
(eg /proc/$$/fd/*
) seems to open an extra file descriptor for the glob, so ls
seems the best solution here.
Update
For further information on the portability of /proc/$$/fd
, please see Portability of file descriptor links. If /proc/$$/fd
is unavailable, then a drop in replacement for the $(ls /proc/$$/fd)
, using lsof
(if that is available) would be $(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-)
.
Best Answer
Yes, this will list all open file descriptors:
Of course, as usual: 0 is stdin, 1 is stdout and 2 is stderr.
The 4th is an open file (to write) in this case.