1. Introduction
When using the bash shell, the process of our shell may come to have various open files for many reasons. These open files each have a corresponding file descriptor integer that Linux’s User space uses to identify the specific file when communicating with Kernel space via system calls or library calls.
In this tutorial, we’re going to discuss how to view the open file descriptors of a bash session from within that bash session itself.
2. Using ls
We can use the ls command to list directories and files within a given directory. Also, the kernel exports information about all of the running processes on a Linux system via the proc pseudo filesystem.
This filesystem is almost always mounted at /proc by default. We can take advantage of the information exported under /proc and combine it with the ls command to list the open file descriptors of a process.
In the /proc pseudo filesystem, we can find the open file descriptors under /proc/
Thus, we can use the ls command and the $$ expression to display the file descriptors of the current bash sessions and the files that they refer to:
$ ls -la /proc/$$/fd/
total 0
dr-x------ 2 user user 0 Apr 7 17:14 .
dr-xr-xr-x 9 user user 0 Apr 7 17:14 ..
lrwx------ 1 user user 64 Apr 7 17:14 0 -> /dev/pts/50
lrwx------ 1 user user 64 Apr 7 17:14 1 -> /dev/pts/50
lrwx------ 1 user user 64 Apr 7 17:14 2 -> /dev/pts/50
lrwx------ 1 user user 64 Apr 7 17:14 255 -> /dev/pts/50
lr-x------ 1 user user 64 Apr 7 17:14 3 -> /tmp/testfile2
l-wx------ 1 user user 64 Apr 7 17:14 4 -> /tmp/testfile1
3. Using lsof
The lsof command lists information about open files for running processes on the system.
When we run lsof without any arguments, it displays the open files of every process running on the system. This will also make lsof run in “repeat” mode, which will cause the output to loop. However, we don’t have to worry about repeat mode too much, as the following commands will prevent that.
We can tell lsof to only list the open files of our bash session’s process by using the -p option in combination with the $$ shell expression that we used with ls:
$ lsof -p $$
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 14928 user cwd DIR 252,1 4096 4060 /tmp
bash 14928 user rtd DIR 252,1 4096 2 /
bash 14928 user txt REG 252,1 1113504 32 /bin/bash
bash 14928 user mem REG 252,1 47568 26949 /lib/x86_64-linux-gnu/libnss_files-2.27.so
bash 14928 user mem REG 252,1 97176 26946 /lib/x86_64-linux-gnu/libnsl-2.27.so
bash 14928 user mem REG 252,1 47576 26951 /lib/x86_64-linux-gnu/libnss_nis-2.27.so
bash 14928 user mem REG 252,1 39744 26947 /lib/x86_64-linux-gnu/libnss_compat-2.27.so
bash 14928 user mem REG 252,1 1516558 30707 /usr/lib/locale/C.UTF-8/LC_COLLATE
bash 14928 user mem REG 252,1 2030928 26939 /lib/x86_64-linux-gnu/libc-2.27.so
bash 14928 user mem REG 252,1 14560 26942 /lib/x86_64-linux-gnu/libdl-2.27.so
bash 14928 user mem REG 252,1 170784 2104 /lib/x86_64-linux-gnu/libtinfo.so.5.9
bash 14928 user mem REG 252,1 179152 26935 /lib/x86_64-linux-gnu/ld-2.27.so
bash 14928 user mem REG 252,1 199772 30708 /usr/lib/locale/C.UTF-8/LC_CTYPE
bash 14928 user mem REG 252,1 50 30720 /usr/lib/locale/C.UTF-8/LC_NUMERIC
bash 14928 user mem REG 252,1 3360 30724 /usr/lib/locale/C.UTF-8/LC_TIME
bash 14928 user mem REG 252,1 270 30715 /usr/lib/locale/C.UTF-8/LC_MONETARY
bash 14928 user mem REG 252,1 48 30714 /usr/lib/locale/C.UTF-8/LC_MESSAGES/SYS_LC_MESSAGES
bash 14928 user mem REG 252,1 34 30722 /usr/lib/locale/C.UTF-8/LC_PAPER
bash 14928 user mem REG 252,1 1683056 4354 /usr/lib/locale/locale-archive
bash 14928 user mem REG 252,1 62 30718 /usr/lib/locale/C.UTF-8/LC_NAME
bash 14928 user mem REG 252,1 131 30705 /usr/lib/locale/C.UTF-8/LC_ADDRESS
bash 14928 user mem REG 252,1 47 30723 /usr/lib/locale/C.UTF-8/LC_TELEPHONE
bash 14928 user mem REG 252,1 23 30713 /usr/lib/locale/C.UTF-8/LC_MEASUREMENT
bash 14928 user mem REG 252,1 26376 27208 /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
bash 14928 user mem REG 252,1 252 30709 /usr/lib/locale/C.UTF-8/LC_IDENTIFICATION
bash 14928 user 0u CHR 136,50 0t0 53 /dev/pts/50
bash 14928 user 1u CHR 136,50 0t0 53 /dev/pts/50
bash 14928 user 2u CHR 136,50 0t0 53 /dev/pts/50
bash 14928 user 3r REG 252,1 5 150 /tmp/testfile2
bash 14928 user 4w REG 252,1 0 2230 /tmp/testfile1
bash 14928 user 255u CHR 136,50 0t0 53 /dev/pts/50
We see from the output that the previous command includes more open files than those that our file descriptors reference.
To address this, we can make lsof only show numeric file descriptors by specifying a range from 0 to INT_MAX.
Thus, we use the -d option to specify a range of file descriptors in the next example. Again, we use the -p option to specify the PID. We then combine this with the -a option to “and” (or combine) these selections together:
$ lsof -a -d 0-2147483647 -p $$
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 14928 user 0u CHR 136,50 0t0 53 /dev/pts/50
bash 14928 user 1u CHR 136,50 0t0 53 /dev/pts/50
bash 14928 user 2u CHR 136,50 0t0 53 /dev/pts/50
bash 14928 user 3r REG 252,1 5 150 /tmp/testfile2
bash 14928 user 4w REG 252,1 0 2230 /tmp/testfile1
bash 14928 user 255u CHR 136,50 0t0 53 /dev/pts/50
4. Conclusion
In this article, we’ve learned that we can use both the ls and lsof commands to list the open file descriptors in the current bash session. We can use the ls command to parse /proc manually and display our open file descriptors. Alternatively, we can leave it up to lsof and provide the PID of the current bash session.