Finding Processes by Files and Ports
pgrep answers “is a process with this name running.” Plenty of real problems start from the opposite direction: you know a file or a port is the problem, and you need to find out which process is behind it. “Address already in use.” “Device is busy.” A log file you can’t delete because something’s still writing to it. This chapter covers the two tools built for exactly that — searching by what’s being used, not by process name.
Everything Is A File — Including Network Connections
This chapter leans on an idea that’s been implicit for Linux. An enormous range of things are represented as file-like objects that a process can open — regular files, directories, devices, and, less obviously, network sockets. A process with an open TCP connection is, from the kernel’s perspective, holding something conceptually similar to an open file. This is exactly why lsof — “list open files” — is also the standard tool for inspecting network connections, not just files on disk.
lsof: List Open Files
Run with no arguments, lsof lists every open file held by every process on the system — a genuinely enormous, mostly unfiltered wall of output. In practice, you’ll almost always run it against something specific.
Finding What’s Using A Specific File
lsof /var/log/syslogThis shows every process currently holding that file open — useful the moment you hit “file is busy” or “permission denied” errors that don’t make sense given the permissions you’ve already checked.
Reading The Output
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
rsyslogd 612 root 7w REG 259,1 88210 131074 /var/log/syslog| Column | Meaning |
|---|---|
COMMAND | The process name holding this open |
PID | Its process ID — feed this straight into the ps -p or kill commands |
USER | Who owns the process |
FD | File descriptor number, and how it’s open — r (read), w (write), u (read/write) |
TYPE | What kind of thing this is — REG (regular file), DIR, IPv4/IPv6 (network socket), and others |
DEVICE | The device number where the file or resource resides. For example, 259,1 identifies a particular block device |
SIZE/OFF | The file size in bytes, or the file offset for certain types of open files. For some resources, it may be 0 or - |
NODE | The inode number for a file, or another identifier for resources that don’t use regular filesystem inodes |
NAME | The actual file path, or for network connections, the address and port |
That FD column matters more than it looks — 7w tells you not just that rsyslogd has this file open, but that it has it open for writing, which is exactly the kind of detail that explains why you can’t also write to it yourself right now.
Finding What’s Using A Port
This is one of the most common reasons to reach for lsof at all — a service fails to start with an “address already in use” error, and you need to know what’s already occupying that port.
sudo lsof -i :8080-i filters to network connections, and :8080 narrows it to that specific port. You’ll typically need sudo here, since seeing another user’s network connections requires elevated privileges the same way seeing their processes fully often does.
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python3 2044 you 3u IPv4 38291 0t0 TCP *:8080 (LISTEN)That LISTEN at the end tells you this process is waiting for incoming connections on that port — exactly what you’d expect from a server. Now you know both the process name and PID responsible, which is everything you need to either investigate it further or stop it.
A Few More Common Filters
lsof -u aliceEvery file currently open by processes belonging to alice.
lsof -p 2044Every file a specific, already-known PID has open — the reverse direction from searching by file, useful once ps or pgrep has already given you a PID and you want to know what it’s touching.
fuser: A Simpler, More Targeted Tool
Normal Usage
lsof is comprehensive but verbose. fuser answers a narrower question more directly: which process IDs are using this specific file or mount point, with less output to parse through.
fuser ~/demo/simplefileOutput:
/home/you/demo/simplefile: 10249 11383This prints just the PIDs using that file — no table, no columns, just the numbers, ready to feed into another command if needed.
Verbose Output
Add -v for a more readable, verbose form closer to lsof’s output:
fuser -v /var/log/syslogOutput:
USER PID ACCESS COMMAND
/home/iamalice/demo/simplefile:
iamalice 10249 F.... hangaround
iamalice 11383 F.... hangaroundReading The ACCESS Column
That F.... isn’t decoration — each position represents a different way a process can be using the target, and more than one can apply at once:
| Letter | Meaning |
|---|---|
c | The process has this as its current working directory |
e | The process is executing this file as its running program |
f | The process has this file open (shown alongside other letters; plain read access on its own is often just left blank) |
F | The process has this file open for writing |
r | The process is using this as its root directory (relevant in a chroot) |
m | The process has this mapped into memory (mmap) — common for shared libraries |
A dot in any position simply means that particular access type doesn’t apply. F.... in the example above means: open for writing, nothing else — exactly what you’d expect from the hangaround example process actively writing to that file. Seeing an e instead, for instance, would tell you a completely different story — that some running program’s actual executable is that file, not just a file it has open.
fuser Can Send Signals, Not Just Report
This is the part lsof can’t do at all: fuser can terminate every process using a target directly, with -k:
sudo fuser -k ~/demo/simplefileThis sends a termination signal to every PID using that file, all at once — no need to extract PIDs and pass them to kill yourself. By default this sends SIGTERM, the same graceful-termination signal you’ll get the full explanation of in the Understanding Signals file coming up shortly in this section; you can specify a different one the same way kill accepts signal names, covered properly there too:
sudo fuser -k -TERM ~/demo/simplefile
sudo fuser -k -KILL ~/demo/simplefileWarning
-k kills every matching process immediately, with no per-process confirmation by default — genuinely risky against something like a mount point with several unrelated processes touching it. Add -i (interactive) to be prompted before each individual kill, which is worth making a habit rather than an afterthought:
sudo fuser -ki ~/demo/simplefileThis is exactly the same caution that applies to pkill and killall in the Killing Processes chapter later in this section — a command that can act on multiple matched processes at once deserves the same “verify before you act” discipline as any of them.
Filtering By Protocol: -4, -6, -n
When checking a port, fuser needs to know which network namespace and IP version you mean, since the same port number can be in use over TCP and UDP simultaneously, or over both IPv4 and IPv6:
sudo fuser -n tcp 8080/tcp
sudo fuser -4 8080/tcp
sudo fuser -6 8080/tcp-n tcp (or -n udp) makes the namespace explicit rather than relying on the /tcp or /udp suffix alone; -4/-6 narrow results to just that IP version, useful when a port shows unexpected results because something’s bound to it over the version you weren’t expecting.
A Real Example: Can’t Unmount A Device
Recall mounting from the Storage section later in this course — occasionally you’ll try to unmount something and get a “device is busy” error, because some process still has a file open somewhere inside that mount point. fuser handles this exact case cleanly with -m (mount point):
fuser -vm /mnt/usb-driveThis shows every process with anything open anywhere under /mnt/usb-drive — even a file several directories deep — which is precisely why the unmount is failing. With the ACCESS column now understood, you can tell at a glance whether a process merely has something open for reading (f) versus actively writing (F) or has that mount point as its current directory (c) — genuinely useful context for deciding whether it’s safe to just kill it or better to let it finish first.
fuser For Ports
sudo fuser 8080/tcpSame underlying question as lsof -i :8080, answered more tersely — just the PID, nothing else, which is often all you actually need once you already know what you’re looking for. Combine with everything above — -v for detail, -k/-i to act on it directly — once you know exactly which port and process you’re dealing with.
lsof vs. fuser: Which One To Reach For
lsof | fuser | |
|---|---|---|
| Output detail | Rich — user, file descriptor mode, type, full path | Minimal — mostly just PIDs |
| Best for | Investigating what a process is doing with a file or port | Quickly answering who is using it, especially mount points |
| Learning curve | More columns to interpret | Faster to read at a glance |
In practice: reach for fuser when you already know exactly what you’re checking and just want the PID fast — a busy mount point, a specific port. Reach for lsof when you need more context — multiple processes might be involved, or you need to see how something is open, not just that it’s open.
What’s Next
You now have three complementary ways to find a process: by name or pattern (pgrep), by the file or port it’s using (lsof/fuser), and by scanning the full picture (ps). The next chapter adds a fourth angle entirely — watching processes live, as their resource usage changes in real time, with top and htop.