Linux file descriptors are the small numeric handles that processes use to access open files, pipes, sockets, and other kernel-managed resources. Every time a program reads a configuration file, writes a log, or communicates through a network socket, file descriptors can be part of the operation.
For a Linux administrator, understanding these handles makes several familiar problems easier to explain: why a process keeps a deleted log file open, how two commands communicate through a pipe, and what an application means when it reports Too many open files.
This lesson explains the underlying model, shows how to inspect it using standard Linux interfaces, and introduces a safe exercise that opens and closes a descriptor without changing system configuration.
- Quick Answer
- What You’ll Learn
- What Are Linux File Descriptors?
- File Descriptor Numbers Are Process-Local
- Why Descriptors 0, 1, and 2 Are Special
- File Descriptors Are Not the Same as Open Files
- A Filename Can Disappear While the File Remains Open
- How to Inspect Linux File Descriptors
- Inspect Your Current Shell
- Inspect Another Process
- Inspect Open Resources with lsof
- Why Network Sockets Also Use File Descriptors
- Linux File Descriptors and Open-File Limits
- Soft Limit vs. Hard Limit
- Inspect a Running Process’s Limits
- What Does “Too Many Open Files” Mean?
- A Safer Diagnostic Sequence
- Mini Lab: Open and Close a File Descriptor
- Lab Objective
- Step 1: Create a Temporary Workspace
- Step 2: Open Descriptor 3
- Step 3: Inspect the Open Descriptor
- Step 4: Read Through Descriptor 3
- Step 5: Close the Descriptor
- Step 6: Clean Up
- Common Linux File Descriptor Mistakes
- 1. Assuming Every Descriptor Is a Disk File
- 2. Treating a Descriptor Number as a Global Identifier
- 3. Confusing Open-File Limits with Disk Capacity
- 4. Assuming a Deleted File Has Released Its Storage
- 5. Changing Limits Before Investigating Resource Usage
- 6. Assuming Your Shell’s Limits Apply to Every Service
- When Should You Use Each Inspection Tool?
- Knowledge Check
- Servers Academy — Key Takeaway
- Official References
Quick Answer
A file descriptor is a nonnegative integer that a process uses to refer to an open resource. Linux maintains a descriptor table for the process, allowing a program to read, write, or perform other operations through those references.
Descriptors 0, 1, and 2 conventionally represent standard input, standard output, and standard error. Other descriptors can represent regular files, pipes, sockets, and additional resources.
Use /proc/PID/fd/ to inspect a process’s descriptor entries and /proc/PID/limits to inspect its resource limits. The optional lsof utility provides another way to investigate open resources.
What You’ll Learn
- What a file descriptor represents inside a Linux process.
- How descriptors relate to files, pipes, and network sockets.
- Why file descriptor numbers are local to a process.
- How to inspect descriptors through
/procandlsof. - What soft and hard open-file limits mean.
- How to investigate a possible descriptor leak without changing production settings.
What Are Linux File Descriptors?
A program needs a way to refer to resources it has opened. Rather than repeatedly identifying a file by its pathname, a program can ask the kernel to open it and then work through the descriptor returned by that operation.
The Linux open() system call, for example, returns a nonnegative integer when it successfully opens a file. Subsequent operations can use that integer to identify the open resource.
Simplified conceptual model. The kernel also maintains open-file descriptions and other objects behind these references.
Think of a descriptor as a handle rather than the resource itself. The number tells the process which open connection to use. It is not the file’s name, inode number, or permanent identity.
This builds on the distinction introduced in Linux Processes Explained. A process is a running program with its own execution state and resources. File descriptors are one part of that state.
File Descriptor Numbers Are Process-Local
Suppose two separate processes both have descriptor 5 open. The numbers match, but they do not necessarily refer to the same resource.
Each process has its own descriptor context. Descriptor 5 in one process may refer to a log file, while descriptor 5 in another may refer to a network socket.
Processes can also intentionally share open resources through mechanisms such as inheritance or descriptor passing. Therefore, equal descriptor numbers do not prove sharing, and different descriptor numbers do not necessarily prove that the underlying open resource is different.
A descriptor number is meaningful only in the context of the process that owns it. To understand what a descriptor refers to, identify both the process and the descriptor.
Why Descriptors 0, 1, and 2 Are Special
Linux programs commonly begin with three standard streams already connected by the environment that launches them.
| Descriptor | Standard Stream | Common Purpose |
|---|---|---|
0 |
stdin | Input to the program |
1 |
stdout | Normal program output |
2 |
stderr | Diagnostics and errors |
These numbers describe conventional roles, not fixed physical destinations. In an interactive terminal, standard input may be connected to your terminal, while standard output and standard error normally appear in the same terminal window.
Redirection changes those connections.
printf '%s\n' "Server ready" > status.txt
In this example, Bash opens status.txt for output and arranges for the command’s standard output to write there.
The command does not need to know whether descriptor 1 points to a terminal or a file.
For a fuller explanation of redirection order, pipes, and standard streams, read Linux Standard Streams Explained.
File Descriptors Are Not the Same as Open Files
The distinction between a descriptor and an open file description is important when investigating Linux behavior.
A descriptor is the process-facing reference. An open file description is a kernel-maintained object containing information associated with the open instance, including file status flags and, where applicable, a current file offset.
Several descriptors may refer to the same open file description. For example, duplicating a descriptor with the dup() family of system calls can create another descriptor that shares the underlying open-file state.
By contrast, opening the same pathname independently can produce separate open file descriptions, each with its own file offset.
This helps explain why reading through one duplicated descriptor can affect where a subsequent read through another duplicated descriptor begins.
A Filename Can Disappear While the File Remains Open
Linux separates pathnames from open references to filesystem objects.
Consider a running application that has opened a log file. If its pathname is removed, the application may still hold an open descriptor referencing the underlying file.
As a result, removing the pathname does not necessarily release the file’s storage immediately. Reclamation can be delayed while open references remain.
The related lesson on hard links, symbolic links, and inodes explains why a pathname and a filesystem object are different concepts.
For administrators, this distinction matters when disk usage remains unexpectedly high after a large log file has been deleted.
How to Inspect Linux File Descriptors
On Linux systems with the usual procfs interface available, the directory /proc/PID/fd/ exposes descriptor entries for a process.
Each entry is named after a descriptor number and commonly appears as a symbolic link describing the referenced resource.
Inspect Your Current Shell
In Bash, $$ identifies the current shell process for this basic inspection.
printf 'Shell PID: %s\n' "$$"
ls -l "/proc/$$/fd"
The output will depend on your environment.
You may see descriptor entries pointing to terminal devices, pipes, or files. This is an observation of the current process state, not a permanent inventory.
The open descriptors of a running process can change while you inspect them.
Inspect Another Process
If you know the PID of a process and have permission to inspect it, replace 1234 below with the real PID.
ls -l /proc/1234/fd
You may encounter several kinds of entries.
| Example Target | What It Suggests |
|---|---|
/var/log/app.log |
An open filesystem object associated with that path. |
pipe:[...] |
A pipe endpoint. |
socket:[...] |
A socket object. |
anon_inode:[...] |
A kernel object represented through an anonymous inode interface. |
A socket entry does not automatically reveal the remote address or application protocol. You may need additional networking information to understand the connection.
Linux also exposes descriptor-related details through /proc/PID/fdinfo/, including information such as the file position and flags for supported descriptor types.
These interfaces are part of the broader virtual filesystem model described in Linux File System Explained.
Access to another process’s descriptor information can be restricted by permissions, security policies, process namespaces, or the way /proc is mounted.
Inspect Open Resources with lsof
The lsof utility provides a convenient human-readable view of open resources.
If it is installed, use:
lsof -p 1234
Replace 1234 with the PID you want to investigate.
The output can identify regular files, sockets, libraries, and other process-related resources.
Remember that not every row corresponds to one ordinary numeric file descriptor. Entries describing the current working directory, executable text, or memory mappings can also appear.
Therefore, counting every lsof row is not a reliable way to determine how many numeric descriptors a process currently holds.
The utility is optional and may not be installed on a minimal server image.
Why Network Sockets Also Use File Descriptors
A file descriptor does not have to refer to a regular file stored on disk.
Linux also uses descriptors for sockets, allowing applications to interact with network connections through kernel-managed handles.
A web server, for example, may hold a listening socket and additional sockets associated with accepted connections.
As the server handles more connections, its descriptor usage may grow. The exact relationship depends on application architecture and connection management.
This connects directly to
Linux Ports and Sockets Explained,
which covers listening addresses, connection states, and the ss command.
A TCP port number identifies a transport-layer endpoint. A file descriptor is a process-local handle used to access a socket object. They are related, but they are not the same identifier.
Linux File Descriptors and Open-File Limits
Processes cannot necessarily open an unlimited number of file descriptors.
Linux provides a per-process resource limit called RLIMIT_NOFILE. It constrains the descriptor numbers that a process can allocate.
Administrators commonly encounter this limit through the shell’s ulimit builtin or the process information exposed under /proc.
Soft Limit vs. Hard Limit
A resource limit has two values.
The soft limit is the value enforced during normal operation.
The hard limit is the ceiling to which an unprivileged process can generally raise its soft limit, subject to the applicable rules.
In Bash, inspect the current shell’s open-file limits with:
ulimit -Sn
ulimit -Hn
These commands display the soft and hard limits, respectively. They do not change the values.
The numbers vary by distribution, service configuration, and execution environment.
Inspect a Running Process’s Limits
For a running process, examine:
cat /proc/1234/limits
Replace 1234 with the real PID.
Look for the Max open files entry. The output reports the process’s soft and hard limits.
This is more useful than assuming a running service has the same limits as your interactive shell.
A service manager, container runtime, or other launching environment may establish limits independently of the terminal session you are using.
Changing ulimit in your shell does not retroactively change the limits of an unrelated service that is already running.
What Does “Too Many Open Files” Mean?
An application may report Too many open files when it cannot allocate another descriptor because it has reached its per-process limit.
The corresponding Linux error is commonly EMFILE.
A separate error, ENFILE, indicates exhaustion of a system-wide open-file resource limit.
These conditions are different from running out of free disk space.
Imagine a long-running service that opens a connection for each incoming request but fails to release certain connections after use.
Over time, its descriptor usage could increase until opening another socket or file fails.
This is a hypothetical example, not a measured incident. The point is the troubleshooting sequence: increasing a limit may postpone a failure without fixing a resource leak.
A Safer Diagnostic Sequence
- Identify the affected process and verify the reported error.
- Inspect the process’s current descriptor entries.
- Check its soft and hard open-file limits.
- Look for unexpectedly large or growing groups of files or sockets.
- Review application behavior, connection lifecycle, and relevant logs.
- Consider changing limits only after understanding the expected workload and the cause of the resource use.
Do not immediately raise system-wide limits or restart critical services without first establishing what is happening.
A restart may temporarily release open resources, but it can also destroy evidence of how the problem developed.
Mini Lab: Open and Close a File Descriptor
Lab Objective
Create a temporary text file, open it through an additional Bash descriptor, inspect the connection, read its contents, and close the descriptor.
This exercise requires Bash and a Linux system with /proc available. It does not require administrator privileges.
Run the commands in one disposable lab shell, not in a critical automation session.
Step 1: Create a Temporary Workspace
SA_FD_LAB=$(mktemp -d)
printf '%s\n' "descriptor demo" \
> "$SA_FD_LAB/note.txt"
printf 'Workspace: %s\n' "$SA_FD_LAB"
The file is created only inside the newly generated temporary directory.
Step 2: Open Descriptor 3
exec 3< "$SA_FD_LAB/note.txt"
This Bash redirection opens the file for reading on descriptor 3 in the current shell.
The command does not replace your shell with another program. The exec builtin can also apply redirections to the current shell.
Step 3: Inspect the Open Descriptor
ls -l "/proc/$$/fd/3"
readlink "/proc/$$/fd/3"
The descriptor entry should point to the temporary text file.
This demonstrates the relationship between a numeric handle and an open resource.
Step 4: Read Through Descriptor 3
IFS= read -r sa_line <&3
printf 'Read: %s\n' "$sa_line"
You should see:
Read: descriptor demo
Bash reads the file through descriptor 3 rather than opening the pathname again for this read.
Step 5: Close the Descriptor
exec 3<&-
The descriptor is now closed in the shell.
To confirm the descriptor entry is gone:
if test -L "/proc/$$/fd/3"; then
printf 'Descriptor 3 is still open\n'
else
printf 'Descriptor 3 is closed\n'
fi
Expected result:
Descriptor 3 is closed
Step 6: Clean Up
First confirm that the saved path is the temporary workspace created in Step 1.
printf 'Cleaning: %s\n' "$SA_FD_LAB"
Then remove only the practice file and its empty directory:
rm -- "$SA_FD_LAB/note.txt"
rmdir -- "$SA_FD_LAB"
unset SA_FD_LAB sa_line
The exercise demonstrates the descriptor lifecycle: open → inspect → read → close.
Common Linux File Descriptor Mistakes
1. Assuming Every Descriptor Is a Disk File
Descriptors can represent sockets, pipes, and other resources. A high descriptor count does not automatically mean an application has opened thousands of ordinary files.
2. Treating a Descriptor Number as a Global Identifier
Descriptor 4 in one process is not automatically related to descriptor 4 in another.
3. Confusing Open-File Limits with Disk Capacity
A process can exhaust available descriptors while substantial disk space remains free.
4. Assuming a Deleted File Has Released Its Storage
Open references may keep the underlying file object alive after its pathname disappears.
5. Changing Limits Before Investigating Resource Usage
Raising a descriptor limit may be appropriate for a legitimate workload, but it should not be the first response to unexplained growth in open resources.
6. Assuming Your Shell’s Limits Apply to Every Service
Always inspect the running process. Services can inherit resource limits from different execution environments.
When Should You Use Each Inspection Tool?
| Question | Useful Tool |
|---|---|
| Which descriptors does a process currently hold? | /proc/PID/fd/ |
| What additional descriptor information is exposed? | /proc/PID/fdinfo/ |
| Which files and resources are associated with a process? | lsof -p PID |
| What open-file limits apply to a process? | /proc/PID/limits |
| What limits apply to this Bash shell? | ulimit -Sn and ulimit -Hn |
| Which network sockets are listening or connected? | ss |
Each tool answers a different question. Start with the process and symptom, then choose the inspection method that reveals the relevant layer.
Knowledge Check
Try answering these questions before opening the explanations.
1. Why can two processes both use descriptor 5 without referring to the same file?
Descriptor numbers are interpreted within a process’s descriptor table. Equal numeric values in different processes do not establish that their resources are related.
2. Why is a file descriptor different from a filename?
A filename is a pathname used to locate a filesystem object. A descriptor is an existing process-level reference to an open resource. The reference can remain valid even if the original pathname changes or disappears.
3. Can a network connection consume a file descriptor?
Yes. Linux applications access socket objects through file descriptors. A descriptor therefore does not have to represent a regular file.
4. Why might changing ulimit in your terminal not fix a running server?
The existing server process may have inherited limits from another environment. Changing the limits of your interactive shell does not retroactively modify an unrelated running process.
5. What should you investigate before increasing an open-file limit?
Check the affected process, its current limit, the kinds of resources it holds, whether usage is growing unexpectedly, and whether the application is releasing resources correctly.
6. Does an lsof output row always represent one numbered file descriptor?
No. The utility can also show resources such as working directories, executable references, and memory mappings. Not every row is one numeric descriptor.
Servers Academy — Key Takeaway
A Linux file descriptor is a process-local handle to an open resource. The process uses a small integer to refer to something the kernel manages, whether that resource is a file, pipe, socket, or another supported object.
The most useful mental model is to separate three things: the process, its descriptor table, and the underlying resource. They are connected, but they are not interchangeable.
For administration, start with observation. Inspect /proc/PID/fd/, examine the process’s actual limits, and identify the resources involved before changing configurations or restarting workloads.
Official References
The following primary technical references document the underlying Linux interfaces and commands.
- Linux man-pages — open(2) — file descriptors and open file descriptions.
- Linux man-pages — dup(2) — descriptor duplication and shared open-file state.
- Linux man-pages — proc_pid_fd(5) — inspecting a process’s descriptor entries.
- Linux man-pages — proc_pid_fdinfo(5) — additional descriptor information.
- Linux man-pages — getrlimit(2) — resource limits and RLIMIT_NOFILE.
- Linux man-pages — proc_pid_limits(5) — viewing a process’s soft and hard limits.
- lsof(8) Manual — listing open files and process-related resources.








