lsof
lsof (LiSt Open Files) is a command-line utility for Unix-like operating systems that displays information about files and other resources opened by running processes, including regular files, directories, sockets, device files, and streams.[1] It operates by reading kernel memory to identify open file descriptors, file types, sizes, offsets, and associated process details such as command names, process IDs, and user ownership.[1] By default, lsof lists all open files system-wide when invoked without arguments, but it supports extensive filtering options to target specific processes, users, file paths, or network connections, making it invaluable for system administration and debugging tasks like identifying resource leaks or blocking processes.[2]
Originally developed by Victor A. Abell, a computer science professor at Purdue University, lsof was first released in 1994 and has since become a standard tool across various Unix dialects.[3] Abell maintained the project for decades, focusing on portability and accuracy in reporting kernel-level file information, with the source code evolving to support dialects including Linux, FreeBSD, macOS (Darwin), NetBSD, OpenBSD, and Solaris/OpenIndiana.[4] Following Abell's retirement, maintenance transitioned to the open-source lsof-org team via GitHub in 2022, where the project continues with bug fixes, enhancements, and community contributions while preserving the original codebase in a "legacy" branch.[4]
Key features of lsof include its ability to handle diverse file types beyond traditional files, such as Internet sockets for network diagnostics (e.g., via the -i option to list TCP/UDP connections) and executable libraries or memory-mapped files.[1] It provides formatted tabular output by default but offers parsable formats (e.g., -F for scripting) and repeat modes (e.g., +r for periodic updates), enabling integration with tools like awk or monitoring scripts.[5] lsof is typically installed via package managers on supported systems—such as apt install lsof on Debian-based distributions or yum install lsof on Red Hat—and requires root privileges for comprehensive system-wide scans due to access restrictions on kernel data.[3]
In practice, lsof aids in scenarios like locating processes holding a file open (e.g., lsof /path/to/file), detecting unlinked but still-accessible files consuming disk space, or troubleshooting network issues by revealing listening ports and remote connections.[2] Its cross-platform support and lightweight design have made it a staple in sysadmin toolkits, with ongoing development ensuring compatibility with modern kernels and security models.[4]
Overview
Purpose and Functionality
lsof, an acronym for "LiSt Open Files," is a command-line utility designed to display information about files opened by processes on Unix-like operating systems.[6] Developed by Victor A. Abell in the early 1990s, it provides detailed output on various file types, including regular files, directories, block and character special files (devices), sockets, libraries, and streams.[6][1]
In Unix-like systems, the design principle that "everything is a file" treats diverse system resources uniformly through file descriptors, encompassing not only traditional files but also devices, inter-process communication channels, and network connections represented as sockets.[2] This abstraction simplifies system interactions but makes monitoring open files essential for understanding resource usage across processes.[2]
At its core, lsof identifies which processes are accessing specific files or resources, enabling system administrators to troubleshoot issues, perform security audits by detecting unauthorized file access, and manage resources such as locating files in use before unmounting filesystems.[1][7][8]
Basic Syntax
The basic syntax of the lsof command follows the form lsof [options] [names], where options are flags that modify the command's behavior and names are positional arguments used to specify targets such as file paths.[3] This structure allows users to invoke lsof flexibly, with options controlling aspects like output format or filtering criteria, while positional names primarily target specific files or devices by their paths (e.g., lsof /var/log/[syslog](/page/Syslog) to list processes using that file).[1]
When invoked without any arguments, lsof lists all open files belonging to all active processes owned by the current user.[3] To target other selectors beyond file names, such as process IDs (PIDs), user IDs (UIDs), or command names, dedicated options are used as positional-like selectors: for example, -p PID specifies one or more PIDs (e.g., lsof -p 1234), -u UID targets user IDs or login names (e.g., lsof -u [root](/page/Root)), and -c command filters by command names (e.g., lsof -c sshd).[1] These selectors enable precise invocation by combining them with the general syntax, such as lsof -p 1234 /etc/passwd to check a specific file's usage within a given process.[3]
Full system visibility requires elevated privileges, as non-root users are restricted to their own processes due to security configurations in most distributions; running lsof with sudo (e.g., sudo lsof) grants root access to display open files across all processes.[1] Options like -i for internet files can be incorporated into this syntax for targeted listings, though their detailed effects are covered elsewhere.[3]
History and Development
Origins
lsof was developed by Victor A. Abell at Purdue University Computing Center in the early 1990s.[6] Abell, serving as associate director, created the tool as a utility for listing information about files opened by processes on Unix systems. In multi-user environments, diagnosing resource usage could be challenging due to limitations of contemporary tools like ps and netstat, which lacked comprehensive details on file descriptors including regular files, directories, sockets, and devices.[9] lsof addressed these gaps, aiding system administration and debugging.
The first public release of lsof, version 2.0, took place in 1994 and was made available as open-source software under a permissive license granted by the Purdue Research Foundation.[10] This license allowed broad distribution and modification without the restrictions typical of copyleft agreements, facilitating its integration into various Unix distributions.[11] Early versions focused on core Unix dialects such as BSD and System V Release 4, with initial testing conducted on platforms like AIX and Solaris to ensure compatibility across diverse environments.[9]
lsof saw adoption in various settings, including at Purdue University, where it was used to investigate process-file interactions.[10] Its utility was enhanced by contributions from users who provided testing and porting support for additional platforms.[9]
Key Releases
lsof's development has seen several milestone releases that introduced significant enhancements to its functionality and compatibility. Version 4.0 marked a major update in the late 1990s, with the version 4 series beginning around 1999, including early support for IPv6 networking in dialects like AIX 4.3.x, FreeBSD, and Linux, allowing lsof to display IPv6 socket information alongside traditional IPv4 details.[12] Version 4.89, released on July 7, 2015, focused on improved portability across Unix dialects, with updates to build processes and support for newer compilers, making it easier to compile on modern systems like AIX 7.x.[13]
Subsequent releases in the 4.9x series addressed evolving system requirements. Version 4.99, first appearing in late 2023, brought compatibility with Linux kernel 6.x through fixes for kernel interface changes, ensuring reliable file listing on recent distributions.[14] Following Victor A. Abell's retirement, maintenance of lsof transitioned in 2023 to the open-source lsof-org team on GitHub.[4] Key enhancements in this era included better handling of containerized environments, such as Docker, by recognizing namespace-isolated files and processes for more accurate output in virtualized setups.[15] Support for additional file types expanded in the 2000s and beyond, with lsof leveraging kernel APIs to report on devices like USB-mounted filesystems when accessed via standard paths such as /dev or mounted directories. Bug fixes targeted platform-specific issues, including segmentation faults on FreeBSD and backend improvements for macOS using libproc for process file enumeration.[16][15]
Maintenance of lsof remains active under the lsof-org project on GitHub, building on the foundational work by Victor A. Abell at Purdue University, where distributions were historically hosted via FTP.[6] There is no formal semantic versioning scheme; instead, revisions follow a sequential numbering pattern, with incremental updates released as needed for bug fixes and compatibility. Deprecated features include the removal of support for obsolete Unix variants like DEC OSF/1, Tru64 UNIX, and OpenStep/NextStep starting in version 4.97, streamlining the codebase for contemporary platforms. As of November 2025, the latest stable release is version 4.99.5, incorporating ongoing refinements for performance and dialect support.[14]
Installation and Availability
lsof provides primary support for all major Unix-like operating systems, including various Linux distributions such as Ubuntu and Red Hat, BSD variants like FreeBSD and OpenBSD, Solaris, AIX, NetBSD, and Darwin-based systems.[4][1] This compatibility stems from its design to interface with kernel structures across these dialects, ensuring it can list open files and related resources effectively on production environments. As of 2024, maintenance includes fixes and autotools support for AIX 7.2 and 7.3.[14]
In the Apple ecosystem, lsof is natively available on macOS, which is built on the Darwin kernel. It can be updated via package managers like Homebrew.[4][17] Adaptations for Darwin allow it to handle macOS-specific file descriptors, such as those for kernel extensions and system services.[14]
Limited or partial support exists for non-native environments, including Windows through emulation layers like Cygwin, which provides a POSIX-compliant interface, or Windows Subsystem for Linux (WSL), where lsof runs within the Linux subsystem. On Android, lsof is not included by default but can be installed in Linux-compatible environments such as Termux or compiled from source, requiring root access for comprehensive functionality.[4]
lsof's portability relies heavily on POSIX standards for core operations, supplemented by compile-time flags and dialect-specific code to accommodate variations in kernel APIs and file system implementations across supported platforms. This approach enables building tailored versions for optimal performance and feature access on each system, while avoiding dependencies on proprietary elements.[4]
Installation Methods
lsof is commonly installed using system package managers on supported Unix-like operating systems, providing a straightforward method to obtain the tool without manual compilation. On Debian and Ubuntu distributions, administrators can install it via the Advanced Package Tool (APT) by executing the command sudo apt update && sudo apt install lsof. This package is maintained in the official Debian repositories and includes the latest stable version compatible with the distribution. Similarly, on Red Hat Enterprise Linux, CentOS, and Fedora systems, lsof is available through the Yellowdog Updater, Modified (YUM) or DNF package managers; the installation command is sudo dnf install lsof (or sudo yum install lsof on older systems where YUM is the default). For macOS users, Homebrew serves as the primary package manager, allowing installation with brew install lsof, which fetches the tool from the official Homebrew formulae repository.[17]
For systems requiring the most recent version or custom configurations, lsof can be compiled from source code. The official distribution is hosted on GitHub under the lsof-org organization, where the latest release can be downloaded as a tarball from the releases page.[14] After extraction, the build process for modern systems (Linux, Darwin/macOS, FreeBSD, NetBSD) uses Autotools: run ./configure to prepare the build for the target dialect, followed by make to compile, and make install to install the binary (typically requiring root privileges). Older versions or legacy dialects may use the ./Configure <dialect> script instead, such as ./Configure linux for Linux systems, before proceeding with make and make install.[18] This method ensures compatibility with specific kernel versions but requires development tools like GCC or Clang, Make, and optionally libtirpc for enhanced RPC support.
lsof is often pre-installed by default on many Linux distributions and macOS, eliminating the need for manual setup in standard environments. For instance, it is included in the base system of major Linux distros like Ubuntu, Fedora, and Red Hat Enterprise Linux, as well as in macOS's command-line tools.[19] To verify availability, users can check with which lsof to locate the binary or run lsof -v to display the version information if installed.[1]
Updates to lsof are typically handled through the respective package managers to apply security patches and minor enhancements; for example, on Debian-based systems, sudo apt update && sudo apt upgrade lsof retrieves the latest packaged version. For source-built installations, manual recompilation from the updated GitHub release is recommended to incorporate new features or fixes not yet in distribution repositories.[18]
Usage and Options
Command-Line Options
The lsof command supports a variety of command-line options to customize the selection, display, and behavior of the open files listing. These options allow users to target specific processes, users, commands, or resources while modifying the output format for efficiency or parsing. Core selection options focus on process and file descriptor criteria, while modifiers adjust display details and resource targeting enables network-specific queries.[1]
Core options enable precise filtering by process attributes. The -p option specifies one or more process IDs (PIDs) to include or exclude in the listing; for example, -p 123 selects files open by process 123, while -p ^123 excludes it, and multiple PIDs can be comma-separated like -p 123,456.[1] The -u option targets files by user login names or user IDs (UIDs), such as -u abe for a specific user or -u ^root to exclude the root user, with comma-separated sets supporting both names and numeric UIDs.[1] Similarly, -c selects processes by command name prefix, like -c sshd for all processes starting with "sshd", and supports negation with ^ or regular expression matching when prefixed with /, as in -c /^sshd/.[1] The -d option limits output to specific file descriptors, such as -d 0 for standard input or -d cwd,1-3 for current working directory and descriptors 1 through 3, with ranges and negations available via ^.[1]
Display modifiers optimize output for readability or programmatic use. The -l flag inhibits the conversion of user IDs to login names, displaying numeric UIDs instead to avoid potential lookup delays or errors.[1] The -n option suppresses domain name service (DNS) lookups for network addresses, presenting numeric IP addresses and port numbers directly to improve performance on systems where name resolution might be slow.[1] For machine-readable output, -F specifies a list of fields to include, prefixed by identifiers like p for PID or f for file type, producing a format suitable for parsing by scripts, with each field terminated by a newline or NUL character if specified.[1]
Resource-specific options target particular file types. The -i flag selects Internet socket files, optionally filtered by protocol, address, or port, such as -i [TCP](/page/TCP):80 for TCP connections on port 80 or -i @1.2.3.4 for a specific IP address, supporting IPv4, IPv6, and combinations like -i [UDP](/page/UDP):[email protected].[1] The -a option enforces logical AND between multiple selection criteria, ensuring only files matching all specified conditions are listed, rather than the default OR behavior.[1]
Help and verbose options provide utility information. The -h flag outputs a brief usage summary, listing available options without executing the full command.[1] The -V option displays the lsof version and reports details on items that could not be located, such as inaccessible PIDs or files, aiding in debugging.[1]
Filtering Capabilities
lsof provides flexible filtering mechanisms by allowing users to combine selection options, which by default operate under an OR logic to display the union of matching open files. For instance, specifying both -p 1234 to select files associated with process ID 1234 and -c sshd to select files from processes executing commands starting with "sshd" will list files that match either criterion.[1] This default behavior enables broad queries, but for more precise targeting, the -a option switches to AND logic, requiring files to satisfy all specified selectors; thus, lsof -p 1234 -c sshd -a restricts output to files open by the specific process 1234 only if it is running an sshd command.[1] Similarly, combining -u root (files owned by user root) with -i TCP (Internet socket files using TCP) under -a yields only TCP socket files belonging to root processes.[1]
Advanced selectors further refine queries by targeting specific attributes. The +D /path option enables recursive searching of a directory tree for open files, useful for identifying all instances of files within a subtree like /tmp; for example, lsof +D /tmp lists every open file descending from that directory.[1] To filter by network-related file types, the -i option selects Internet socket files, optionally filtered by protocol, address, or port, such as -i TCP:80 for TCP connections on port 80. The -U option selects UNIX domain socket files exclusively.[1] The -b option prevents lsof from blocking on inaccessible devices or filesystems, such as stalled NFS mounts, allowing queries to proceed without interruption; an example is lsof -b /nfs/mount/point to list open files on a potentially unresponsive network filesystem.[1] For device-specific filtering, -N includes NFS files that might otherwise be omitted, ensuring comprehensive coverage in networked environments.[1]
Performance optimizations are integral to effective filtering, particularly for large systems. The -n option skips hostname and service name resolution for network files, significantly reducing execution time by avoiding DNS lookups; this is especially beneficial in commands like lsof -i -n for quick network connection scans.[1] Additionally, +c 0 displays full command names in the output without truncation (default is 9 characters), aiding identification during complex filters such as lsof -c ssh -a +c 0 to reveal complete process names matching the pattern.[1]
Error handling in filtering supports streamlined output for scripting or integration. The -t option produces terse listings of only process identifiers (PIDs), suppressing headers and full details, which is ideal for piping to other tools; for example, lsof -t /specific/[file](/page/File) returns PIDs of processes holding that file open, enabling actions like kill -HUP $(lsof -t /u/abe/bar).[1] When combined with selectors, -t maintains the filtering logic while minimizing verbosity, such as lsof -t -p 1234 -a -i [TCP](/page/TCP) to get PIDs for a process's TCP sockets only.[1]
Output Interpretation
Field Descriptions
The standard output of the lsof command is presented in a tabular format with fixed-width columns that provide key details about open files and associated processes.[1] These columns are aligned and separated by spaces, allowing for easy parsing and readability.[1] The following table describes the primary fields in this output:
| Field | Description |
|---|
| COMMAND | The name of the process, truncated to the first nine characters of the executable command associated with the process.[1] |
| PID | The process identifier (PID) number assigned to the process.[1] |
| USER | The user identifier (UID) or login name of the process owner.[1] |
| FD | The file descriptor, which may be a number (e.g., 0 for standard input), or special values such as cwd (current working directory), txt (executable text), mem (memory-mapped file), or rtd (root directory).[1] This field also includes access mode indicators like r (read), w (write), u (read and write), or a space (unknown mode), followed by lock status if applicable (e.g., N for NFS lock, R for read lock on the entire file).[1] |
| TYPE | The type of the file, such as REG (regular file), DIR (directory), CHR (character special file), BLK (block special file), FIFO (named pipe), PIPE (unnamed pipe), LINK (symbolic link), IPv4 or IPv6 (Internet socket), or unix (Unix domain socket).[1] |
| DEVICE | The device on which the file resides, represented by major and minor device numbers in hexadecimal format (e.g., 08:02).[1] For special files, it may show identifiers like -> for links or socket details.[1] |
| SIZE/OFF | The size of the file in bytes for regular files, or the file offset (current position) if the -o option is used; the column header changes to OFFSET with -o or SIZE with -s.[1] For non-regular files like sockets or pipes, this field displays available content amounts from kernel buffers if determinable, though accuracy varies by system dialect.[1] |
| NODE | The inode number of the file (in decimal) or, for sockets, the protocol type (e.g., TCP, UDP) or a special identifier like * for unknown.[1] This can be expanded with the +f n option to include node details.[1] |
| NAME | The full name of the file, including path for disk files, or detailed connection information for network sockets (e.g., local and remote addresses with ports, such as *:http->example.com:12345); for pipes or FIFOs, it may indicate linked processes or endpoints.[1] |
Specialized handling appears in certain fields depending on the file type. For Internet sockets, the NODE field indicates the protocol (e.g., TCP), while the NAME field provides endpoint details including local address and port, remote host and port (if connected), and connection state (e.g., ESTABLISHED); the -T option can enhance the display with additional TCP/TPI information, such as queue sizes and window sizes, in the NAME field.[1] For pipes (TYPE PIPE), the NAME field shows the other endpoint's process details (e.g., pcmd for the command at the other end), and offsets may reflect read/write positions if available.[1]
The output format is customizable to refine field content. The -o option forces display of the file offset in all cases, using a 0t (decimal) or 0x (hexadecimal) prefix, while -o0 specifies unlimited decimal digits before switching to hexadecimal, ensuring consistent offset representation even for non-regular files where offsets might otherwise be omitted or approximate.[1] Access modes in the FD field, such as r/w, directly indicate the permissions under which the file is opened, aiding in security analysis.[1] Column headers (e.g., COMMAND, PID) are included by default in the standard tabular output to facilitate interpretation.[1] The -w option suppresses warning messages that could interfere with the output, preserving the clean display of these fields.[1]
Sample Outputs
The default output of the lsof command displays a table of open files across all processes, with columns including the command name, process ID, user, file descriptor, type, device, size/offset, node, and name. This format provides a comprehensive view but can be lengthy on active systems. For illustration, consider a simplified example focusing on the init process, which represents a basic system process opening essential files like directories and executables.[20]
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 root cwd DIR 253,0 4096 2 /
init 1 root rtd DIR 253,0 4096 2 /
init 1 root txt REG 253,0 145180 147164 /sbin/init
init 1 root mem REG 253,0 1889704 190149 /lib/libc-2.12.so
init 1 root 0u CHR 1,3 0t0 3764 /dev/null
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 root cwd DIR 253,0 4096 2 /
init 1 root rtd DIR 253,0 4096 2 /
init 1 root txt REG 253,0 145180 147164 /sbin/init
init 1 root mem REG 253,0 1889704 190149 /lib/libc-2.12.so
init 1 root 0u CHR 1,3 0t0 3764 /dev/null
In this output, "COMMAND" indicates the process name (e.g., init), "PID" the process ID (e.g., 1), "USER" the owner (e.g., root), "FD" the file descriptor (e.g., cwd for current working directory, txt for executable text, 0u for standard input with read/write access), "TYPE" the file type (e.g., DIR for directory, REG for regular file, CHR for character device), "DEVICE" the device number, "SIZE/OFF" the file size or offset (e.g., 0t0 for zero size with no offset), "NODE" the inode number, and "NAME" the file path. These fields align with the definitions outlined in the Field Descriptions section.[20]
For network-focused output, the lsof -i option filters to show only Internet socket files, such as TCP connections, revealing listening ports and remote details. A representative example involves an SSH server listening on port 22, demonstrating how lsof captures protocol, address family, and connection state.[20]
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1471 [root](/page/Root) 3u IPv4 12683 0t0 [TCP](/page/TCP) *:ssh (LISTEN)
sshd 1471 [root](/page/Root) 4u [IPv6](/page/IPv6) 12685 0t0 [TCP](/page/TCP) *:ssh (LISTEN)
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1471 [root](/page/Root) 3u IPv4 12683 0t0 [TCP](/page/TCP) *:ssh (LISTEN)
sshd 1471 [root](/page/Root) 4u [IPv6](/page/IPv6) 12685 0t0 [TCP](/page/TCP) *:ssh (LISTEN)
Here, the output highlights network-specific details: "TYPE" as IPv4 or IPv6 for address family, "NAME" including the protocol (TCP), local port (ssh or 22), and state (LISTEN for waiting connections). No remote client is shown in listening mode, but established connections would include source and destination IP:port pairs (e.g., 192.168.1.100:ssh->192.168.1.200:12345 (ESTABLISHED)). For a web server scenario, replacing :22 with :80 would similarly list processes like httpd or nginx bound to port 80.[20]
When run without sufficient privileges (e.g., as a non-root user), lsof encounters permission errors, resulting in incomplete output with explicit denial messages for inaccessible paths or directories. This occurs because lsof relies on reading /proc entries, which are restricted for other users' processes. A sample output from a non-root execution shows such failures for system processes like init.[21]
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 root cwd unknown /proc/1/cwd (readlink: Permission denied)
init 1 root rtd unknown /proc/1/root (readlink: Permission denied)
init 1 root txt unknown /proc/1/exe (readlink: Permission denied)
init 1 root NOFD /proc/1/fd (opendir: Permission denied)
kthreadd 2 root cwd unknown /proc/2/cwd (readlink: Permission denied)
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 root cwd unknown /proc/1/cwd (readlink: Permission denied)
init 1 root rtd unknown /proc/1/root (readlink: Permission denied)
init 1 root txt unknown /proc/1/exe (readlink: Permission denied)
init 1 root NOFD /proc/1/fd (opendir: Permission denied)
kthreadd 2 root cwd unknown /proc/2/cwd (readlink: Permission denied)
Annotations include (readlink: Permission denied) for failed path resolutions and (opendir: Permission denied) for inaccessible file descriptor directories, marked as unknown or NOFD (no file descriptors). To mitigate these without elevating privileges, the -b option instructs lsof to avoid certain kernel functions like readlink(2) and stat(64), skipping problematic entries silently instead of reporting errors. For instance, lsof -b on the same system would omit the denial messages and list only accessible files, though at the cost of incomplete paths (e.g., showing device numbers without full names).[1]
The -F option produces a parsable, field-oriented output suitable for scripting, where each line begins with a single-character identifier for the field (e.g., p for PID, c for command, f for file descriptor, n for name), followed by the value, enabling easy parsing with tools like AWK or Perl. Specifying subsets like -Fpcfn limits to process ID, command, file descriptor, and name. A basic example for a process might appear as:[1]
p315
cinit
fcwd
n/
p315
cinit
fcwd
n/
This format groups fields per open file instance, with a newline separating records; for scripting, it allows extraction without column parsing, such as grepping for p lines to get PIDs. The full set of field identifiers (e.g., a for access mode, t for type) is documented in the man page for custom selection.[1]
Practical Applications
Process Monitoring
lsof serves as a vital tool for monitoring active processes by revealing the files, sockets, and other resources they hold open, enabling administrators to assess resource allocation and detect anomalies in real-time or targeted inspections.[1] By specifying process identifiers (PIDs), users can isolate and examine individual processes without scanning the entire system, which is particularly useful for identifying inefficiencies or potential issues in resource-intensive applications.[1]
To identify resource hogs, such as processes consuming excessive file descriptors, the -p option allows listing open files for a specific PID; for instance, lsof -p 1234 displays all resources used by process ID 1234, including the count and types of open files.[1] In a database server context, this can reveal open files contributing to high resource usage. For example, in Oracle Database environments, lsof helps track open files per process to diagnose descriptor limits.[22] The output includes columns for command, PID, user, and file descriptors, providing a snapshot of potential bottlenecks without requiring additional tools.[1]
Detecting orphan files—those deleted but still held open by processes—is achieved by filtering lsof output for the "(deleted)" marker in the NAME column, commonly via lsof | [grep](/page/Grep) deleted, which lists processes retaining space on disk despite file removal.[23] This command identifies culprits like long-running services or errant applications, allowing targeted restarts to reclaim storage; for example, it might show a web server process holding a large deleted log file.[23]
For real-time process monitoring, lsof integrates with the watch utility to periodically refresh output, such as watch lsof -i to observe evolving network-related file activity tied to processes, updating every few seconds to track dynamic resource engagement.[1] Alternatively, lsof's built-in repeat mode with -r (e.g., lsof -p 1234 -r 10) automates refreshes at set intervals, aiding in proactive observation of process behavior over time without scripting.[1]
In security contexts, lsof facilitates checks on unknown or suspicious processes by listing their open files with options like -p PID or -u username, helping spot malware through unusual file accesses, such as unexpected network sockets or hidden executables.[24] For instance, examining files opened by an unidentified PID can reveal connections to malicious payloads or unauthorized data exfiltration attempts, as recommended in incident response practices.[25] This approach, combined with user or PID filtering, supports auditing without full system scans, emphasizing process-specific anomalies.[1]
System Troubleshooting
lsof serves as a vital diagnostic tool for resolving file lock contention, where processes hold exclusive access to files, preventing operations like updates or deletions. Administrators frequently encounter "file in use" errors during software installations or system maintenance; executing lsof /path/to/[file](/page/File) reveals the processes and file descriptors involved, such as a package manager holding a lock on /var/lib/[dpkg](/page/Dpkg)/lock.[1][2] This output includes the process ID (PID), command name, and lock status (e.g., 'w' for write lock), enabling targeted termination of the offending process via kill to release the lock without rebooting.[1] For instance, in a scenario where an interrupted update leaves a lock file inaccessible, lsof identifies the stale process, restoring system functionality.[5]
Detecting potential memory leaks often involves scrutinizing open file handles, as applications may accumulate excessive descriptors without closing them, leading to resource exhaustion. By running lsof -p PID on a suspected process, users can inspect the SIZE and OFF columns, which display the file size and offset; unusually large values, such as gigabytes in log accumulators like /var/log/app.log, signal unchecked growth from unrotated or leaking files.[2] Similarly, lsof | grep deleted uncovers files marked for deletion but still held open, consuming disk space akin to a leak until the process exits.[5] This approach helps quantify the scale of the issue, where hundreds of open descriptors per process exceed typical limits (e.g., 1024 default ulimit), prompting code reviews or restarts to mitigate performance degradation.[1]
Network-related troubleshooting with lsof excels at pinpointing port conflicts and persistent connections that disrupt services. The command lsof -i :port lists processes bound to a specific port, such as port 80 for HTTP, displaying details like the listening PID and connection state (e.g., ESTABLISHED or LISTEN); this resolves errors where a new web server fails to bind due to a lingering process from a prior instance.[1][2] For hanging connections in database services, filtering with lsof -i TCP:3306 reveals idle sockets, allowing administrators to identify and close them to free resources and restore responsiveness.[5] Such diagnostics prevent cascading failures, as unresolved conflicts can lead to service downtime affecting multiple users.
Post-reboot boot-time issues, such as stuck filesystem mounts or inaccessible device files, can be diagnosed by scanning for residual open handles with lsof +D /, which recursively examines the entire root directory tree for open files and directories.[1] This reveals processes clinging to unmounted devices, like an init script holding a reference to /dev/sda1, causing delays in subsequent mounts or boot completion. By including options like -x fl to cross mount points, lsof uncovers hidden dependencies, such as NFS shares with stale locks, enabling manual unmounts via umount -l or process kills to expedite recovery.[1] In environments with complex boot sequences, this method provides a comprehensive view without invasive kernel debugging, ensuring quicker resolution of hangs that prolong startup times.[2]
Limitations and Alternatives
Known Limitations
lsof exhibits several inherent limitations stemming from its reliance on operating system privileges, kernel interfaces, and platform-specific implementations. When executed by non-root users, lsof is restricted to displaying only open files belonging to processes with the same user ID as the invoking process, due to security measures like the HASSECURITY compilation option, which prevents unauthorized access to other users' process information. This privilege gap means that files opened by processes running under different user IDs, including setuid or setgid binaries, may remain invisible unless lsof is run with elevated privileges, as access to /proc//fd directories for other users requires root permissions.[1][26]
Kernel dependencies further constrain lsof's accuracy and completeness. On customized or modified kernels, rapid changes in kernel memory structures can lead to unpredictable or incomplete output, as lsof parses kernel data directly via /dev/kmem or /proc interfaces, and mismatches between build-time headers and runtime kernel versions may cause failures. In containerized environments like Docker, network namespaces obscure socket information, resulting in incomplete listings such as unidentified 'sock' entries or empty output for lsof -i, since processes in isolated namespaces appear detached from the host's view of PIDs and file descriptors. Additionally, lsof lacks native support for kernel-level files or structures without corresponding loadable modules, limiting visibility into dynamically loaded components like AFS volumes where node numbers may be blank without kernel address access.[1][26][27]
Performance overhead becomes noticeable on systems with high resource utilization, particularly on Linux where lsof scans the /proc filesystem for every active PID to enumerate open files. This process can take several minutes and consume nearly 100% CPU on servers with thousands of processes or open file descriptors, as each /proc entry requires stat() calls and memory parsing, exacerbating delays during peak loads. Options like +D for directory descent amplify this issue on large filesystems, demanding significant dynamic memory and time.[28][29][1]
Portability challenges arise across UNIX dialects and non-POSIX systems, where certain command-line options and features, such as IPv6 support or the +m option for mount points, are unavailable or behave differently due to varying kernel name caches and device numbering schemes. For instance, path name components for advanced filesystems may not be resolvable on dialects like AIX or OpenBSD, and lsof's effectiveness diminishes on very recent filesystem implementations where kernel integration lags, as seen in incomplete reporting for snapshot-based structures. These variations are detailed in platform-specific documentation, underscoring lsof's optimization for standard POSIX environments over diverse or emerging ones.[1][26]
Several command-line utilities complement or serve as alternatives to lsof for investigating file and network usage in Unix-like systems. The fuser command identifies processes using specific files, sockets, or file systems by listing their process IDs (PIDs) along with access types, such as open files or current directories.[30] Unlike lsof, which provides comprehensive details including command names, user IDs, and file descriptors, fuser offers a simpler output focused on PIDs and is particularly useful for quickly identifying and killing processes to unmount busy file systems, such as with the -k option to send SIGKILL signals.[31]
For block device management, lsblk lists storage devices, partitions, and mount points in a tree structure, providing details like file system types and sizes without focusing on open file usage.[32] In contrast, lsof's -i option reveals network sockets (TCP/UDP) tied to specific processes, offering process-level insights that lsblk lacks for block devices.[32] Basic socket statistics can be obtained via netstat or its modern replacement ss, which display active connections, ports, and states. With the -p option (requiring elevated privileges), ss can show process names and PIDs associated with sockets, though it provides less detailed file descriptor and open file information compared to lsof, making it suitable for high-level network diagnostics.[33][34]
In programmatic contexts, the Python library psutil serves as a cross-platform alternative by enabling scripts to retrieve open files per process, including paths, file descriptors, and modes, similar to lsof's output but integrated into application code for automation.[35] For dynamic tracing of file operations, strace monitors system calls like open() in real-time for running processes, capturing new file accesses that lsof's snapshot view might miss, though it generates verbose logs requiring filtering for usability.[36]
lsof often pairs with complementary tools for broader system analysis, such as top or htop to correlate PIDs with resource usage, or auditd to log file access events persistently across sessions.[37]