Basically, it lists open files that match given selectors.
To start simple, we can list all the files that are currently open by processes running as a specified user:
# lsof -u syslog
...or we can ask “which processes have these file open?” like this:
# lsof /var/log/*
You can also ask the question the other way round: which files does this process have open? To do this you need to know the process ID:
# pgrep nmbd
1121
# lsof -p 1121
Here, we’re asking what files the Samba daemon nmbd has open. If you try this command (or something like it) you’ll discover that lsof has a pretty liberal idea of what an “open file” means. It not only shows you the regular files (open on a file descriptor) but also the current directory of a process, any shared libraries it has attached (there are probably quite a few), memory-mapped files, pipes, and any TCP or UDP endpoints it has open.
Talking of endpoints, we can see all the open TCP or UDP sockets like this:
# lsof -i
I find this command really useful when troubleshooting an unresponsive service.
You can use it to answer the question “is the service actually listening on the port it’s supposed to be listening on?” We could tighten up the query to ask “which process is listening on the secure shell port?” like this:
# lsof -i tcp:22
or equivalently you could ask:
# lsof -i tcp:ssh
It gets more interesting when you start combining selectors. By default the selectors are combined with the OR operation. For example, the following command shows open files that are either UDP sockets, or are opened by processes running as root:
$ sudo lsof -i udp -u root
This is probably not very useful. But if we add a -a option the logic changes to “AND”:
$ sudo lsof -i udp -a -u root
which answers the more useful question “show me the UDP sockets owned by root”.
We can also say “NOT”, like this:
# lsof -i udp -a -u ^root
which shows me all UDP sockets NOT owned by root. We can home in even further.
Here, we’re just asking for UDP sockets bound to the mdns port (port 5353):
# lsof -i udp:mdns -a -u ^root
Normally, the output from lsof is quite verbose. However the -t option tells lsof to just display the PID of the matching process(es):
# lsof -i udp:5353 -t
By itself this perhaps isn’t too useful, but it’s intended to be used with a command substitution, perhaps like this:
# kill -9 $(lsof -i udp:5353 -t)
which will kill all processes listening on UDP port 5353.
As you can see, the command line is starting to look like a mini language in its own right, a bit like the find command. Indeed, the man page for lsof runs to 2,700 lines; it’s a daunting read!