lsof, short for “list open files”, is a command-line utility that reports which processes have which files open on a Linux or other Unix-like system. Because Linux treats regular files, directories, devices, pipes and network sockets as file descriptors, lsof answers a wide range of monitoring questions: which program holds a log file, which process listens on port 443, or why a disk stays full after a large file was deleted.
In Linux monitoring, lsof complements resource-oriented tools such as top, htop, iostat and vmstat. Those tools show how much CPU, memory or I/O is used; lsof shows exactly what each process is touching at a given moment.
How lsof finds open files
On Linux, lsof gathers its data mainly from the /proc filesystem. For each process it reads the symbolic links in /proc/PID/fd, the memory mappings in /proc/PID/maps, and the working and root directories, then resolves socket details from tables such as /proc/net/tcp. The result is a point-in-time snapshot, not a continuous trace.
Visibility depends on privileges. An ordinary user sees full details only for their own processes, while root sees every process on the host. Inside containers, lsof sees only the processes of the container’s PID namespace, which often explains why an expected process is missing from the output.
Reading lsof output columns
Each output line describes one open file of one process. The columns are compact, and two of them, FD and TYPE, carry most of the diagnostic value. The table explains the default columns.
| Column | Meaning | Example value |
|---|---|---|
| COMMAND | First characters of the process name | nginx |
| PID | Process identifier | 1423 |
| USER | Owner of the process | www-data |
| FD | Descriptor number or special role | 4u, cwd, txt, mem |
| TYPE | Kind of file | REG, DIR, IPv4, unix, FIFO |
| DEVICE | Device numbers of the file system | 8,1 |
| SIZE/OFF | File size or current offset | 1048576 |
| NODE | Inode number or protocol | 262147, TCP |
| NAME | Path, address pair or socket state | *:443 (LISTEN) |
In the FD column, a number is a real file descriptor and the following letter shows the access mode: r for read, w for write and u for read and write. Special values describe other relationships: cwd is the current directory, txt the program binary, mem a memory-mapped file such as a shared library, and DEL a mapping of a deleted file. A NAME ending in “(deleted)” marks a file removed from the directory tree that is still held open.
Essential lsof options and filters
Without options, lsof prints every open file on the system, often tens of thousands of lines. Filters narrow the output, and by default multiple filters are combined with OR; adding -a combines them with AND. The table lists the most useful selections.
| Command | What it shows | Typical question |
|---|---|---|
lsof -i :8080 | Processes using port 8080 | What blocks this port |
lsof -iTCP -sTCP:LISTEN -nP | All listening TCP sockets | Which services accept connections |
lsof -p 1423 | Open files of one process | What is this process doing |
lsof -u postgres | Files opened by one user | What does this account touch |
lsof /var/log/app.log | Processes holding one file | Who writes this log |
lsof +D /mnt/data | Open files under a directory tree | Why unmount fails |
lsof +L1 | Open files with zero links | Where deleted space is held |
Two habits make lsof much faster and clearer: -n skips DNS lookups and -P shows port numbers instead of service names. For scripts, -t prints only PIDs, and -F produces a field-based output format that is easier to parse than the aligned columns.
lsof compared with ss, fuser, strace and /proc
Several tools overlap with lsof, and choosing the right one saves time. lsof is the broadest inventory tool, while its neighbors are faster or more specialized for a single question.
| Tool | Strength | When to prefer it |
|---|---|---|
| lsof | All file types with process context | General inventory and diagnosis |
| ss | Very fast socket listing | Large numbers of network connections |
| fuser | PIDs using a file or mount, can signal them | Quick checks before unmounting |
| strace | Live system calls as they happen | Seeing when files are opened |
| /proc/PID/fd | Raw descriptor links, no extra tool | Minimal systems and containers |
The key distinction is snapshot versus timeline: lsof and ss show the current state, while strace shows the sequence of opens, reads and closes over time. For a short-lived process that opens and closes a file within milliseconds, lsof will usually miss the event entirely.
Pitfalls when using lsof
- Running without root hides other users’ processes and makes a busy port look free.
- Network file systems can make lsof hang; a stale NFS mount may block it for minutes, and the
-boption avoids some blocking kernel calls. - Recursive +D on large trees is slow because lsof must stat every file;
lsof /mountpointis faster when the target is a whole mount. - Counting lines is not counting descriptors: memory mappings and threads add rows, so
ls /proc/PID/fd | wc -lgives the true descriptor count for limit checks. - Containers and namespaces hide processes, so lsof should run in the namespace that owns the process.
lsof is also an excellent tool for spotting file descriptor leaks. If the number of open sockets or files of a long-running service grows steadily over hours, the service is likely failing to close resources and will eventually hit its “Too many open files” limit.
A non-technical view
Imagine a library where every book, desk and phone line is recorded on a sign-out sheet. lsof reads that sheet for the computer. It tells an administrator who currently has what: which program is holding a document, which one is answering calls on a certain line, and which one refuses to give something back.
That is useful whenever something seems stuck. If a disk cannot be removed or a program cannot start because “the address is in use”, lsof names the program responsible, so the problem can be solved precisely instead of by restarting everything.
A concrete example
An administrator notices that the root file system of a Linux web server reports 95 percent usage in `df`, while du over the whole disk adds up to only 60 percent. A colleague had deleted a 12 GB debug log the day before, yet the space never came back.
Running lsof +L1 shows the application server still holding /var/log/app/debug.log (deleted) with a size of about 12 GB. Because the process keeps the descriptor open, the kernel cannot free the blocks. Instead of restarting the service at peak time, the administrator truncates the file through its descriptor with : > /proc/2210/fd/7, and usage drops to 60 percent immediately. The team then configures log rotation to signal the service to reopen its logs.