# lsof: какие процессы слушают порт и держат файл

Индекс LLMS: [llms.txt](/llms.txt)

---

Сервис не стартует — порт 8080 занят. Разбираешься, кто именно его держит, и попутно выясняется, что тот же процесс держит конфиг, который ты хотел отредактировать. lsof отвечает на оба вопроса: какие процессы открыли файлы и сокеты.

## Слушающие порты

Классическая задача — найти, кто слушает конкретный порт.

```bash
lsof -i -n -P
```

| Флаг | Действие |
|------|----------|
| `-i` | Показать интернет-сокеты |
| `-n` | Без DNS-резолва (IP вместо hostname) |
| `-P` | Без преобразования портов (80 вместо http) |

Без `-n -P` lsof тратит время на DNS и резолвит порты в имена сервисов из /etc/services. На продакшене это лишние секунды.

Если нужен конкретный порт:

```bash
lsof -i :8080 -n -P
```

> [!TIP]
> Чтобы узнать, какой процесс слушает порт 443, достаточно `lsof -i :443 -n -P`. Вывод покажет PID, пользователя и тип сокета (IPv4/IPv6, TCP/UDP).

Для фильтра по протоколу:

```bash
lsof -i TCP:22 -n -P    # только TCP
lsof -i UDP:53 -n -P    # только UDP
```

## Процессы в директории

Нужно понять, какие процессы работают с файлами внутри директории? `lsof +D` рекурсивно обходит директорию и показывает все открытые файлы.

```bash
lsof +D /var/log/
```

> [!WARNING]
> На директории с тысячами файлов (например, /tmp) команда работает долго. Она обходит файловую систему, а не опрашивает ядро — это O(n) операция.

Для нерекурсивного поиска (только файлы непосредственно в директории, без поддиректорий) используй find + xargs:

```bash
find /etc/nginx -maxdepth 1 -type f -exec lsof {}
```

Результат покажет все процессы, которые держат открытыми файлы из указанной директории. Типичный сценарий — нельзя отмонтировать раздел, потому что кто-то работает с файлами внутри.

## Инвентарь одного процесса

Когда PID известен, полный список открытых файлов:

```bash
lsof -p 1234
```

Вывод включает регулярные файлы, библиотеки (.so), сокеты и pipe. Для быстрого grep по типу:

```bash
lsof -p 1234 | grep REG      # только файлы
lsof -p 1234 | grep FIFO     # pipe
lsof -p 1234 | grep IPv      # сетевые сокеты
```

> [!NOTE]
> REG — Regular file, DIR — directory, FIFO — named pipe, IPv4/IPv6 — сетевые сокеты. TYPE в выводе lsof совпадает с типом в /proc/PID/fd.

Обратная операция — найти PID по файлу:

```bash
lsof /var/log/syslog
```

Если файл занят (ротация логов не проходит, unmount не работает), эта команда покажет виновника.

## Краткий вывод команды

По умолчанию lsof обрезает имя команды до 9 символов. Для длинных имен (java, python) этого может не хватать:

```bash
lsof +c 0 -i -n -P    # показать полное имя команды
lsof +c 20 -p 1234    # до 20 символов
```

```bash
lsof +c 0 -p $(pgrep -f nginx)
```

> [!TIP]
> `+c 0` означает «без ограничения». Удобно при работе с Java-процессами, где в командной строке десятки символов classpath.

## Быстрый справочник

| Команда | Назначение |
|---------|------------|
| `lsof -i :PORT` | Кто слушает PORT |
| `lsof -i TCP` | Все TCP-соединения |
| `lsof -i UDP` | Все UDP-соединения |
| `lsof -p PID` | Файлы процесса PID |
| `lsof +D DIR` | Процессы в директории |
| `lsof /path/to/file` | PID, открывший файл |
| `lsof +c N` | Ограничить имя команды N символами |
| `lsof -u USER` | Все открытые файлы пользователя |
| `lsof -c CMD` | Файлы процессов с именем CMD |

## Типичные ошибки

**lsof не установлен** — на минимальных образах приходится доустанавливать:

```bash
apt install lsof    # Debian/Ubuntu
yum install lsof    # RHEL/CentOS
```

**Нет прав на чтение /proc** — для просмотра чужих процессов нужен root или membership в группе, которая имеет доступ. Обычно это означает запуск через sudo.

**lsof зависает** — ядро не отвечает на запросы файловых дескрипторов (проблемы с NFS, подвисший filesystem). Ctrl+C и перезапуск с таймаутом.

---

lsof — один из тех инструментов, к которым возвращаешься каждый раз, когда разбираешься с заблокированными ресурсами. Три команды покрывают 90% задач: `-i :PORT` для порта, `+D /path` для директории, `-p PID` для процесса.
