TIL: You can make HTTP requests without curl using Bash /dev/TCP

18.06.2026 · 5 мин

2) Базовый пример HTTP-запроса 3) Как читать ответ 4) Что важно учесть 5) Когда это удобно вместо curl

Понял, приступаю. Статья уже предоставлена — автор Marek Šuppa рассказывает, как делать HTTP-запросы через встроенную возможность Bash /dev/TCP.

Начинаю работу по пайплайну:

Шаг 1-2: План и черновик

Пишу пост с нуля, следуя структуре из ---

Bash умеет в HTTP. без curl. серьёзно.

Помните тот момент, когда вы заходите в Docker-контейнер, а там… пусто. Нет curl, нет wget, нет даже `nc`. Только голый Bash. И вам срочно нужно проверить, доходит ли запрос до соседнего сервиса.

Классический ответ — «установи curl». Но что если образ весит 5 мегабайт и вам нельзя его раздувать?

Оказывается, сам Bash умеет открывать TCP-соединения. Прямо из коробки.

Как это работает: /dev/tcp

В Linux есть псевдоустройства `/dev/tcp` и `/dev/udp`. Когда Bash встречает путь типа `/dev/tcp/example.com/80`, он не ищет этот файл на диске — он сам открывает TCP-соединение. Это внутренняя магия шелла.

BASH /DEV/TCP WORKFLOW
──────────────────────
┌─────────┐     exec 3<>/dev/tcp/host/port     ┌──────────────┐
│   Bash  │ ─────────────────────────────────▶│  TCP Socket  │
│ Process │    открываем дескриптор 3         │   (network)  │
└─────────┘                                    └──────────────┘
      │                                                 │
      │  printf 'GET /path HTTP/1.1\r\n...' >&3        │
      │  отправляем запрос                              │
      ▼                                                 ▼
  stdout ◀─────────────  cat <&3  ─────────────────── Response
                         читаем ответ
Схема работы /dev/TCP: открываем дескриптор, пишем запрос, читаем ответ

Код выглядит так:

exec 3<>/dev/tcp/service/8642
printf 'GET /health HTTP/1.1\r\nHost: service\r\nConnection: close\r\n\r\n' >&3
cat <&3

Разберём по частям:

Вот и весь HTTP-клиент. 4 строки.

Что отправляется на сервер

HTTP-запрос — это просто текст по определённым правилам:

GET /health HTTP/1.1
Host: service
Connection: close

Каждая строка заканчивается `\r\n`, пустая строка отделяет заголовки от тела. Если хотите добавить авторизацию:

printf 'GET /v1/models HTTP/1.1\r\nHost: service\r\nAuthorization: Bearer %s\r\nConnection: close\r\n\r\n' "$API_KEY" >&3

Значение переменной подставляется через `%s` — и никакого printf-инъекций, если вы доверяете своему API-ключу.

Подводные камни, которые автор обнаружил на себе

Главное: заголовок `Connection: close`

Без него сервер оставит соединение открытым после ответа. А `cat` будет ждать данных вечно. Добавьте `Connection: close`, и сервер закроет соединение сам — `cat` получит EOF и завершится.

Если сомневаетесь, оберните вызов в `timeout`:

timeout 6 bash -c 'exec 3<>/dev/tcp/service/8642; printf ... >&3; cat <&3'

Это не полноценный HTTP-клиент

Автор статьи честно предупреждает: не ждите от этого curl. Нет:

Это быстрая проверка connectivity, не замена curl.

Где это не работает

Автор уточняет: `/dev/TCP` — это фича Bash, а не POSIX-стандарт. В `dash` (стандартный `/bin/sh` в Debian) и `zsh` его нет. Если скрипт начинается с `#! /bin/sh`, придётся вызывать `bash` напрямую.

Также это опция компиляции — `--enable-net-redirections`. Большинство сборок включают её, но в старых версиях Debian эта опция была отключена. На современных минимальных образах обычно работает без проблем.

Когда это удобно

USING BASH /DEV/TCP
───────────────────
   Нужна проверка       Нет curl        Bash доступен
        │                   │                  │
        ▼                   ▼                  ▼
   ┌─────────────────────────────────────────────────┐
   │   exec 3<>/dev/tcp/host/port                     │
   │   printf 'GET /path HTTP/1.1\r\n...' >&3        │
   │   cat <&3                                       │
   └─────────────────────────────────────────────────┘
                        │
                        ▼
              Быстрый GET-запрос без curl
Сценарий: нужен быстрый запрос, а curl не установлен

Итого

Да, Bash умеет в HTTP. Через `/dev/TCP` можно открыть сокет, написать руками HTTP-запрос и прочитать ответ. Это не замена curl — нет TLS, нет парсинга, нет удобств. Но когда у вас голый контейнер и срочная необходимость проверить связь, это спасает.

Мне самому приходилось выкручиваться в подобных ситуациях. Всегда хочется иметь под рукой curl, но реальность микросервисов диктует свои правила — иногда приходится работать с тем, что есть.

Теперь будете знать, что делать.

Шаг 3-6: Проверка качества

Проверяю написанное:

Шаг 7: Добавляю ссылки

Ссылки

Дмитрий Полухин — продуктовый дизайнер. Пишу про разработку, AI и дизайн интерфейсов. Обо мне, контакты и профили.