What is a file descriptor and why everything in Linux is a file
Published on 2026-09-12 by frfrand
Un número entero que representa cualquier cosa abierta: archivos, sockets, tuberías, el teclado. Por qué esa abstracción hizo tan potente a Unix, y qué significa "too many open files".

"Everything in Unix is a file" is a phrase that is repeated a lot and explained little. The file descriptor is where that idea becomes concrete.
A number, nothing more
When a process opens something, the kernel returns an integer to it: the descriptor. From there on, the process uses that number to read, write, and close.
What is interesting is what can be behind that number: a file on disk, a network connection, a pipe to another process, a device, the keyboard, a timer.
The interface is the same for all. Reading from a file and reading from a socket use the same system call.
The first three are reserved by convention:
0 standard input 1 standard output 2 standard error
And those you open afterwards receive the lowest free number: 3, 4, 5.
Why that abstraction is so powerful
Because it allows programs to be combined without knowing anything about each other.
When you write something like this:
$ cat registro.txt | grep error > salida.txt
what happens is that the shell manipulates descriptors: it connects the output of one to the input of the other through a pipe, and redirects the final output to a file.
Neither cat nor grep know anything about this. Each one reads from its descriptor 0 and writes to its descriptor 1, without realizing what is on the other side. That is, in essence, the reason why the Unix command line is composable.
And explain something that confuses many people: why errors don't go through the pipe. Since they go to descriptor 2 and the pipe connects descriptor 1, error messages keep appearing on screen. That is deliberate: it allows you to see errors even when you are redirecting output.
Too many open files
The error that made the concept famous.
Each process has a limit on open descriptors. By default it is usually 1024, which for a server with many connections quickly becomes insufficient.
View the current limit:
ulimit -n
View how many a specific process has open:
ls /proc/<pid>/fd | wc -l
And see what it has open, which is what really helps:
ls -l /proc/<pid>/fd
That shows each descriptor and what it points to. It is the fastest way to detect a leak: if you see hundreds of descriptors pointing to the same file or to closed sockets, there is code that opens and does not close.
Raising the limit, and the detail that is forgotten
It can be raised in /etc/security/limits.conf, but there is a very common trap: it does not apply to systemd services.
Services need their own setting:
[Service] LimitNOFILE=65535
It is the number one cause of "I raised the limit and it still fails".
A surprising detail
If you delete a file that a process has open, the space is not freed until that process closes it. The name disappears from the directory, but the content remains alive because there is a descriptor pointing to it.
It's the explanation of the classic mystery: you deleted a giant log, "df" still shows the disk full, and "du" doesn't find anything large. The file exists without a name, held by a descriptor.
lsof +L1
lists exactly those cases. The solution is to restart the process that has it open, or ask it to reopen its logs.