Что такое fd
Когда process-and-pid открывает что-то (файл, сокет, pipe) - ядро
возвращает маленькое целое - file descriptor. Дальше процесс
обращается к ресурсу по этому числу: read(fd, ...), write(fd, ...),
close(fd).
fd - индекс в табличке процесса: /proc/<pid>/fd/N указывает на цель.
Три «магических» fd
Каждый запущенный процесс получает три fd по умолчанию:
| fd | имя | по умолчанию |
|---|---|---|
| 0 | stdin | клавиатура (терминал) |
| 1 | stdout | экран |
| 2 | stderr | экран (отдельный поток!) |
Это конвенция Unix: программа читает из 0, пишет результат в 1, ошибки в 2. Шелл умеет перенаправлять каждый поток отдельно.
Перенаправления в bash
cmd > out.log # stdout → файл (= 1>out.log)
cmd 2> err.log # stderr → файл
cmd > all.log 2>&1 # СНАЧАЛА stdout в файл, потом stderr туда же
cmd > out.log 2> err.log # развести по разным
cmd &> all.log # bash-shortcut: и stdout и stderr в один файл
cmd < input.txt # stdin ← файл
cmd << EOF ... EOF # heredoc: stdin ← inline-текст
cmd <<< 'one line' # here-string: stdin ← одна строка
ВАЖНО: 2>&1 означает «продублировать fd 1 в fd 2». Порядок имеет
значение: cmd >file 2>&1 правильно (сначала stdout в файл, потом
stderr в тот же файл), а cmd 2>&1 >file - нет (stderr ушёл туда
где stdout БЫЛ - на терминал).
/dev/null и /dev/stderr
cmd > /dev/null # выкинуть stdout
cmd 2> /dev/null # выкинуть stderr (типичное «не показывай ошибки»)
cmd > /dev/null 2>&1 # выкинуть всё
/dev/null - спецфайл, всё что пишут - теряется; чтение даёт EOF.
Pipe = fd между процессами
ls | grep '.txt'
Шелл создаёт pipe (две связанные fd), форкает оба процесса:
у ls stdout заменён на write-конец pipe, у grep stdin заменён
на read-конец. Получается потоковая передача без файлов.
/proc/<pid>/fd - что открыто прямо сейчас
ls -l /proc/$$/fd/ # fd текущего шелла (symlink'и на цели)
ls -l /proc/$$/fd/0 # обычно → /dev/pts/X (терминал)
ls -l /proc/<pid>/fd/ # любой процесс (нужны права)
Это то же что показывает cmd-lsof -p <pid>.
Лимиты
Сколько fd может одновременно держать один процесс:
ulimit -n # текущий soft-лимит (обычно 1024 или 65535)
cat /proc/sys/fs/file-max # глобальный лимит на ВСЕ процессы
«Too many open files» = упёрлись в лимит. Поднимается через
ulimit -n в shell или LimitNOFILE= в systemd unit.
Дублирование fd: dup2()
Из C-кода - dup2(src, dst) копирует src в dst. Это и есть основа
редиректов: shell делает dup2(open("file"), 1) чтобы перенаправить
stdout процесса перед exec-ом.