Skip to content
Go back

lsof: The Tool That Shows You Everything

By SumGuy 5 min read
lsof: The Tool That Shows You Everything

lsof stands for “list open files,” and honestly, it should be in your Linux starter pack right next to grep and curl. Most sysadmins barely scratch the surface, using it only to find what’s listening on a port. But the tool does way more than that. It’s like having X-ray vision into what your system is actually doing.

Here’s the thing: on Linux, everything is a file. Devices. Network sockets. Pipes. Regular files. When something goes wrong, lsof shows you the evidence. Let me show you the patterns that’ll save you hours of debugging.

The Basics: What Is lsof Doing?

lsof reads the /proc filesystem and shows you every file descriptor open by every process. It’s simple in concept, powerful in practice.

Terminal window
$ lsof -p 1234
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
myapp 1234 root cwd DIR 10,0 4096 256 /home/app
myapp 1234 root rtd DIR 10,0 4096 2 /
myapp 1234 root txt REG 10,0 2097152 1048576 /usr/bin/myapp
myapp 1234 root 0u CHR 1,3 0 6 /dev/null
myapp 1234 root 1w REG 10,0 50000 2000000 /var/log/app.log

Each row is one file descriptor. The columns tell you what process owns it, what the file/socket/device is, and where it lives.

Pattern 1: Find What’s Using a Port

This is the go-to use case. Port 8080 is already listening, and you have no idea why.

Terminal window
$ sudo lsof -i :8080
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python 2341 user 3u IPv4 34567 0t0 TCP *:8080 (LISTEN)

There it is. Process ID 2341, running Python, listening on 8080.

If you need to be more specific:

Terminal window
# Only TCP (not UDP)
$ sudo lsof -i TCP:8080
# Only listening sockets (not established connections)
$ sudo lsof -i :8080 -sTCP:LISTEN
# Find all connections to a specific host
$ lsof -i @192.168.1.100

Pattern 2: Find Files a Process Has Open

Your app is running out of disk space, but du shows nothing obvious. Maybe it’s got a deleted file open that’s still consuming space.

Terminal window
$ lsof -p 5678 | grep deleted
myapp 5678 root 15w REG 10,0 1073741824 5000000 /var/log/old.log (deleted)

There it is. A 1 GB file that was deleted but still open. The inode isn’t cleaned up because the process still has a file handle to it. Kill the process or send it a signal to rotate logs, and the space is freed.

Or just list everything a process has open:

Terminal window
$ lsof -p 5678
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
myapp 5678 root cwd DIR 10,0 4096 256 /home/app
myapp 5678 root 0u CHR 1,3 0 6 /dev/null
myapp 5678 root 1w REG 10,0 50000 2000000 /var/log/app.log
myapp 5678 root 5u REG 10,0 100 998765 /etc/config.yaml
...

Pattern 3: See All Network Connections

No netstat? No problem.

Terminal window
$ lsof -i
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1234 root 3u IPv4 12345 0t0 TCP myhost:ssh->remote:54321 (ESTABLISHED)
nginx 5678 root 6u IPv4 12346 0t0 TCP *:http (LISTEN)
curl 90210 user 3u IPv4 12347 0t0 TCP 192.168.1.5:54321->example.com:443 (ESTABLISHED)

Established connections, listening sockets, pending connections — all in one view.

Pattern 4: Find Which Process Is Holding a File

You’re trying to unmount a filesystem, but it says “device busy.” Something has that directory open.

Terminal window
$ lsof /mnt/data
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 2341 user cwd DIR 15,2 4096 131072 /mnt/data
python 5678 user 5r REG 15,2 50000 65536 /mnt/data/config.yaml

Process 2341 (your shell) has /mnt/data as its current directory. Process 5678 has a file open in it. Kill or redirect them, then the unmount will work.

Pattern 5: See What a Running Service Owns

For services running under their own user:

Terminal window
$ lsof -u postgres
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
postgres 1234 postgres cwd DIR 10,0 4096 256 /var/lib/postgresql
postgres 1234 postgres 0r CHR 1,3 0 6 /dev/null
postgres 1234 postgres 4u REG 10,0 536870912 9999999 /var/lib/postgresql/data/base/1
...

This shows everything the postgres user has open. Useful for diagnostics without having to track a specific PID.

Pattern 6: Recursive Directory Searches

Who has files open under /home/?

Terminal window
$ lsof +D /home/
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 2341 user cwd DIR 10,0 4096 131072 /home/user
python 5678 user 5r REG 10,0 50000 65536 /home/user/script.py
vi 9999 user 1w REG 10,0 0 999999 /home/user/.temp.swp

This recursively walks the directory tree. Slower than specific searches, but powerful for investigation.

The Real-World Scenarios

Debugging port conflicts at startup:

Terminal window
sudo lsof -i :3000 && echo "Port already in use" || echo "Port is free"

Finding zombie processes holding locks:

Terminal window
lsof /var/lock/myapp.lock

Monitoring disk space usage by deleted files:

Terminal window
sudo lsof | grep deleted | awk '{print $7}' | awk '{sum+=$1} END {print sum " bytes"}'

See all open connections to a database:

Terminal window
lsof -i @db.internal.local

Why This Matters

lsof is your window into what Linux is actually doing. Port conflicts, disk space mysteries, hung processes, zombie files — lsof shows the evidence. It’s the first tool I reach for when things aren’t making sense, and it beats guessing every time.

Learn the -p, -i, and +D patterns, and you’ll solve 90% of runtime mysteries. The rest is just reading the output carefully.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it may appear here.


Previous Post
Why Docker Builds Are Slow: Layer Cache Explained
Next Post
Docker Exit Codes: Why Your Container Keeps Restarting

Related Posts