jq: обработка JSON в терминале с примерами
jq — утилита для обработки JSON в терминале. Она форматирует нечитаемый ответ API, достаёт вложенные поля, фильтрует массивы, собирает новые объекты, считает агрегаты и превращает JSON в строки для скриптов. Если вы работаете с curl, логами, Docker, Kubernetes или REST API, jq быстро становится такой же базовой командой, как grep, awk и sed.
Идея простая: на вход jq получает JSON, на выход отдаёт результат применения фильтра — от тривиального «покажи поле status» до сложного «возьми все проверки с кодом не 200, сгруппируй по региону и выведи компактный список». Ниже — примеры: установка, синтаксис, работа с объектами и массивами, API, JSON Lines, опции для скриптов и типовые рецепты для разработчиков и DevOps-инженеров.
Что такое jq и когда он нужен
jq часто называют «sed для JSON», но аналогия неполная. sed работает со строками, а jq понимает структуру JSON: объекты, массивы, строки, числа, true, false, null. Поэтому вместо хрупких регулярных выражений можно обращаться к данным по пути: .user.email, .items[], .checks[] | select(.status != "ok").
Типовые задачи для jq:
1) Быстро посмотреть ответ API — многие API отдают минифицированный JSON в одну строку, а jq '.' форматирует его с отступами и подсветкой в терминале.
2) Достать нужное поле — например, код статуса, ID задачи, токен из ответа, версию релиза, IP контейнера.
3) Отфильтровать массив объектов — найти пользователей с ролью admin, контейнеры в статусе running, проверки с ошибкой, записи логов с уровнем error.
4) Подготовить данные для скрипта — вывести значение без кавычек через -r, проверить условие через -e, собрать TSV/CSV-подобный вывод.
5) Диагностировать сервисы — jq удобно использовать вместе с curl, journalctl, docker inspect, kubectl, gh, aws и другими CLI, которые возвращают JSON.
Если вы уже используете текстовые утилиты, посмотрите также материал про практическую работу с awk. awk хорош для табличного текста и логов, а jq — для структурированного JSON.
Установка jq и базовый синтаксис
В большинстве Linux-дистрибутивов jq ставится из стандартного репозитория.
# Debian, Ubuntu
sudo apt update
sudo apt install jq
# Fedora
sudo dnf install jq
# Arch Linux
sudo pacman -S jq
# macOS через Homebrew
brew install jqПроверить версию:
jq --versionБазовый формат команды:
jq 'фильтр' файл.jsonЕсли JSON приходит из другой команды, используйте pipe:
curl -s https://api.github.com/repos/jqlang/jq | jq '.'Фильтр . означает «вернуть весь входной JSON» — это самый простой способ красиво отформатировать документ:
jq '.' response.jsonДопустим, есть файл service.json:
{
"service": "api",
"status": "ok",
"version": "1.8.3",
"checks": [
{ "name": "database", "status": "ok", "latency_ms": 12 },
{ "name": "redis", "status": "ok", "latency_ms": 3 },
{ "name": "payments", "status": "degraded", "latency_ms": 850 }
]
}Получить поле верхнего уровня:
jq '.status' service.jsonРезультат:
"ok"По умолчанию строки выводятся как JSON-строки — с кавычками. Для shell-скриптов чаще нужен «сырой» вывод:
jq -r '.status' service.jsonРезультат:
okЕсли нужно получить несколько полей, можно собрать новый объект:
jq '{service: .service, status: .status, version: .version}' service.jsonИли вывести строку:
jq -r '"\(.service) \(.version): \(.status)"' service.jsonЗдесь \(...) — интерполяция выражений внутри строки jq.
Навигация по объектам и массивам
Обращение к полям в jq похоже на JavaScript, но это отдельный язык фильтров.
Получить вложенное поле:
jq '.user.profile.email' user.jsonЕсли ключ содержит дефис, пробел или начинается с цифры, используйте квадратные скобки:
jq '.["content-type"]' headers.json
jq '.user["display name"]' user.jsonРабота с массивами:
jq '.checks' service.json
jq '.checks[0]' service.json
jq '.checks[0].name' service.jsonИндексация начинается с нуля. Отрицательный индекс берёт элементы с конца:
jq '.checks[-1]' service.jsonЧтобы пройти по всем элементам массива, используется []:
jq '.checks[]' service.jsonПолучить имена всех проверок:
jq -r '.checks[].name' service.jsonРезультат:
database
redis
paymentsМожно брать срезы:
jq '.checks[0:2]' service.jsonЭто вернёт первые два элемента.
Полезные функции для объектов и массивов:
jq '.checks | length' service.json
jq 'keys' service.json
jq 'has("status")' service.json
jq '.checks | map(.name)' service.jsonlength возвращает длину массива, строки или количество ключей объекта. keys показывает ключи объекта. map(...) применяет выражение к каждому элементу массива и возвращает новый массив.
Если поле может отсутствовать, пригодится безопасный оператор ?:
jq '.user?.email' response.jsonА если нужно значение по умолчанию, используйте //:
jq -r '.user.email // "unknown@example.com"' response.jsonЭто удобно при работе с API, где часть полей может быть null или вовсе отсутствовать в ответе.
Фильтрация и преобразование данных
Сильная сторона jq — фильтры и пайплайны. Как в shell, оператор | передаёт результат одного выражения следующему.
Вывести проверки, у которых статус не ok:
jq '.checks[] | select(.status != "ok")' service.jsonПолучить только имена таких проверок:
jq -r '.checks[] | select(.status != "ok") | .name' service.jsonФильтр по числовому значению:
jq '.checks[] | select(.latency_ms > 100)' service.jsonСобрать новый объект из отфильтрованных данных:
jq '.checks[] | select(.latency_ms > 100) | {name, status, latency_ms}' service.jsonЕсли имя поля в новом объекте совпадает с исходным, можно писать коротко: {name, status}. Если нужно переименовать поле:
jq '.checks[] | {check: .name, state: .status, latency: .latency_ms}' service.jsonДля преобразования массива целиком используйте map:
jq '.checks | map({name, ok: (.status == "ok")})' service.jsonРезультат:
[
{
"name": "database",
"ok": true
},
{
"name": "redis",
"ok": true
},
{
"name": "payments",
"ok": false
}
]Сортировка:
jq '.checks | sort_by(.latency_ms)' service.jsonМаксимальное значение:
jq '.checks | max_by(.latency_ms)' service.jsonСумма задержек:
jq '.checks | map(.latency_ms) | add' service.jsonСреднее значение можно посчитать так:
jq '.checks | (map(.latency_ms) | add) / length' service.jsongroup_by сам сортирует элементы по значению ключа перед группировкой, поэтому отдельный sort_by не нужен:
jq '.checks | group_by(.status) | map({status: .[0].status, count: length})' service.jsonjq вместе с curl и HTTP API
Самый частый сценарий — проверить API через curl и сразу разобрать ответ. Если вы редко используете curl, начните с гайда что такое curl и как им пользоваться.
Пример: получить информацию о репозитории GitHub и вывести только нужные поля:
curl -s https://api.github.com/repos/jqlang/jq \
| jq '{name, description, stars: .stargazers_count, forks}'Флаг -s отключает прогресс-бар curl, чтобы он не мешал JSON. В скриптах часто добавляют -S и -f:
curl -sSf https://example.com/health | jq '.'-f заставляет curl завершиться с ошибкой при HTTP-кодах 400 и выше. Это удобно в проверках, но помните: тело ответа при ошибке может не попасть в пайп.
Проверить health endpoint и вернуть код завершения в зависимости от JSON-поля:
curl -sSf https://example.com/health \
| jq -e '.status == "ok"' > /dev/nullОпция -e делает jq полезным для shell-условий: если результат false или null, команда завершится с ненулевым кодом.
if curl -sSf https://example.com/health | jq -e '.status == "ok"' > /dev/null; then
echo "service is healthy"
else
echo "service is unhealthy"
fiТакой скрипт не заменяет внешний мониторинг доступности: он выполняется только там, где вы его запустили, и не видит проблему со стороны пользователя. Для публичных сайтов обычно нужна отдельная проверка с заданным интервалом — например, Statuser, который регулярно обращается к сайту и присылает уведомление при сбое. А jq полезен на этапе диагностики: быстро посмотреть, что именно вернул endpoint.
Если предпочитаете более читаемый CLI для API, посмотрите статью HTTPie вместо curl. HTTPie тоже хорошо сочетается с jq, если нужно дополнительно фильтровать JSON.
Переменные, аргументы и безопасная подстановка
Новички часто пытаются склеивать фильтр jq строками shell. Это опасно: можно сломать кавычки или получить некорректный JSON. Для передачи значений используйте --arg и --argjson.
Фильтр по имени, которое хранится в переменной shell:
CHECK_NAME="payments"
jq --arg name "$CHECK_NAME" \
'.checks[] | select(.name == $name)' \
service.json--arg всегда передаёт значение как строку. Если нужно число, boolean или объект, используйте --argjson:
LIMIT=100
jq --argjson limit "$LIMIT" \
'.checks[] | select(.latency_ms > $limit)' \
service.jsonПередать несколько параметров:
STATUS="degraded"
LIMIT=500
jq --arg status "$STATUS" --argjson limit "$LIMIT" \
'.checks[] | select(.status == $status and .latency_ms > $limit)' \
service.jsonСоздать JSON из shell-переменных:
SERVICE="api"
STATUS="ok"
VERSION="1.8.3"
jq -n --arg service "$SERVICE" --arg status "$STATUS" --arg version "$VERSION" \
'{service: $service, status: $status, version: $version}'Опция -n запускает jq без входного JSON. Это удобно, когда нужно сгенерировать JSON-объект в скрипте, например для webhook-запроса или тестового payload.
Сравните с ручной сборкой JSON через echo: там легко забыть экранирование кавычек, переносов строк и спецсимволов. jq берёт эту работу на себя.
JSON Lines, логи и большие файлы
Не все JSON-данные хранятся одним документом. В логах часто используется формат JSON Lines: каждая строка — отдельный JSON-объект.
Пример app.log:
{"ts":"2026-01-10T10:00:01Z","level":"info","msg":"started","request_id":"a1"}
{"ts":"2026-01-10T10:00:03Z","level":"error","msg":"database timeout","request_id":"b2"}
{"ts":"2026-01-10T10:00:04Z","level":"warn","msg":"slow response","request_id":"c3","latency_ms":1200}jq умеет читать такой файл построчно:
jq 'select(.level == "error")' app.logВывести компактно, по одному объекту на строку:
jq -c 'select(.level != "info")' app.logОпция -c включает compact output. Она полезна, когда результат снова должен быть JSON Lines.
Сделать читаемый вывод:
jq -r 'select(.level != "info") | "\(.ts) [\(.level)] \(.msg)"' app.logРезультат:
2026-01-10T10:00:03Z [error] database timeout
2026-01-10T10:00:04Z [warn] slow responseЕсли логи идут из journalctl, можно получать JSON и фильтровать его через jq:
journalctl -u nginx.service -o json \
| jq -r 'select(.PRIORITY <= "3") | "\(.__REALTIME_TIMESTAMP) \(.MESSAGE)"'У journalctl своя специфика форматов и полей, поэтому для системных логов пригодится отдельный разбор: анализ логов с помощью journalctl.
Для больших JSON-массивов обычный jq '.items[]' file.json может потреблять много памяти, потому что документ нужно разобрать целиком. В таких случаях лучше, если источник отдаёт JSON Lines. Если это невозможно, посмотрите в сторону потокового режима --stream, но он сложнее: jq будет выдавать пары «путь — значение», а не привычные объекты. Для большинства прикладных задач достаточно JSON Lines и jq -c.
Ещё одна полезная опция — -s, или slurp. Она читает все входные JSON-документы и складывает их в массив:
jq -s 'group_by(.level) | map({level: .[0].level, count: length})' app.logЭто удобно для агрегаций, но на больших логах может съесть много памяти.
Практические рецепты для DevOps и разработки
Ниже — команды, которые часто встречаются в реальной работе.
1) Проверить, что API вернул нужную версию
curl -sSf https://example.com/version \
| jq -e -r '.version == "1.8.3"' > /dev/nullТакую проверку можно встроить в deploy-скрипт после выкладки. Если релиз связан с HTTP API, полезно также понимать, как устроены health checks: об этом есть материал проверка состояния сервисов в Node.js.
2) Получить IP-адрес Docker-контейнера
docker inspect my-container \
| jq -r '.[0].NetworkSettings.Networks | to_entries[0].value.IPAddress'docker inspect возвращает массив, поэтому сначала берём .[0]. Если нужно разобраться с базовыми Docker-командами, пригодится статья основные команды Docker.
3) Показать имена контейнеров и их статусы из JSON
docker ps --format '{{json .}}' \
| jq -r '"\(.Names)\t\(.Status)\t\(.Ports)"'Здесь Docker отдаёт JSON Lines: по одному объекту на контейнер.
4) Найти неуспешные проверки в отчёте мониторинга
jq -r '
.checks[]
| select(.http_status != 200 or .ok == false)
| "\(.name): status=\(.http_status), error=\(.error // "none")"
' report.jsonЭто удобно при разборе инцидента — быстро получить список проблемных URL, регионов или backend-проверок из сохранённого JSON-отчёта.
5) Преобразовать массив объектов в TSV
jq -r '.checks[] | [.name, .status, .latency_ms] | @tsv' service.jsonРезультат можно передать в column:
jq -r '.checks[] | [.name, .status, .latency_ms] | @tsv' service.json | column -t6) Достать уникальные значения
jq '.checks | map(.status) | unique' service.jsonДля строкового вывода:
jq -r '.checks | map(.status) | unique[]' service.json7) Удалить чувствительные поля перед отправкой лога
jq 'del(.password, .token, .headers.authorization)' request.jsonЕсли нужно удалить поле в каждом элементе массива:
jq '.users | map(del(.password_hash, .totp_secret))' users.json8) Объединить несколько JSON-файлов
jq -s 'add' part1.json part2.json part3.jsonДля объектов add объединит ключи. Для массивов — склеит массивы. Если ключи объектов совпадают, значение из более позднего файла перезапишет предыдущее.
9) Отфильтровать Kubernetes pods по фазе
kubectl get pods -A -o json \
| jq -r '.items[] | select(.status.phase != "Running") | "\(.metadata.namespace)/\(.metadata.name): \(.status.phase)"'10) Получить последние версии релизов из GitHub API
curl -s https://api.github.com/repos/jqlang/jq/releases/latest \
| jq -r '.tag_name'Для автоматизации этого обычно добавляют обработку HTTP-ошибок, лимитов API и таймаутов на стороне curl.
Частые ошибки и полезные опции jq
jq лаконичен, но у него есть несколько мест, где легко ошибиться.
1) Забыли -r и получили кавычки
TOKEN=$(jq '.token' response.json)В переменную попадёт строка с кавычками. Правильно:
TOKEN=$(jq -r '.token' response.json)2) Перепутали массив и объект
Если команда .items.name возвращает null, возможно, items — массив. Нужно пройти по элементам:
jq '.items[].name' response.json3) Поле отсутствует, и фильтр ломается дальше по пайплайну
Используйте ? и //:
jq -r '.user?.email // "no-email"' response.json4) Shell съел кавычки
Фильтр jq почти всегда лучше заключать в одинарные кавычки:
jq '.items[] | select(.status == "ok")' file.jsonЕсли внутри нужно значение из shell-переменной, не вставляйте его напрямую — используйте --arg.
5) Нужен код завершения, а не текст
Для проверок в CI/CD и shell-скриптах используйте -e:
jq -e '.ok == true' response.json > /dev/null6) Нужно отключить цветной вывод
Когда результат пишется в файл или передаётся другой программе, цвет обычно отключается автоматически. Но можно явно:
jq -M '.' response.json7) Нужно сохранить порядок и компактность
Компактный JSON:
jq -c '.' response.jsonОтсортировать ключи объектов:
jq -S '.' response.json8) Нужно обработать невалидный JSON
jq строгий: если вход не является валидным JSON, он завершится с ошибкой. Это плюс для скриптов, потому что проблема обнаруживается сразу. Если команда перед jq иногда возвращает HTML-страницу ошибки вместо JSON, сначала проверьте HTTP-код и заголовки. Для диагностики сетевых и HTTP-проблем могут пригодиться материалы про ошибку 502 Bad Gateway и все коды ответов HTTP.
FAQ
Можно ли редактировать JSON-файл через jq на месте?
У jq нет встроенного режима -i, как у sed. Обычно пишут во временный файл, а потом заменяют исходный:
jq '.version = "1.8.4"' config.json > config.tmp && mv config.tmp config.jsonЧем jq отличается от grep для JSON?
grep ищет текст, а jq понимает структуру JSON. Через jq можно безопасно выбрать поле .user.email, отфильтровать массив, проверить тип значения и собрать новый JSON.
Можно ли использовать jq в CI/CD?
Да. Частый сценарий — проверить ответ API, достать версию, прочитать JSON-отчёт тестов или провалить job через jq -e, если условие не выполнено.
Что делать, если JSON слишком большой?
Лучше получать данные в формате JSON Lines и обрабатывать построчно. Для огромных единых JSON-документов можно изучить jq --stream, но его фильтры сложнее обычных.
jq стоит держать в стандартном наборе терминальных инструментов. Он закрывает промежуток между «быстро посмотреть ответ API» и «писать отдельный скрипт на Python или Node.js». Для разовых проверок, диагностики инцидентов, обработки логов и автоматизации деплоя это один из самых полезных CLI-инструментов.
Похожие статьи

Практическая работа с awk. Синтаксис, примеры, паттерны, обработка текстов
Практический разбор awk: как работает синтаксис, паттерны и действия, обработка текстовых файлов и логов в Linux.
17 декабря 20258 мин

Что такое tmux и как удобно работать в терминале с несколькими сессиями
tmux позволяет работать с несколькими сессиями и окнами в одном терминале. Удобно при администрировании серверов и постоянных SSH-подключениях.
15 октября 20255 мин

iostat и iotop: диагностика дисковой нагрузки в Linux
Практический разбор команд iostat и iotop: как читать метрики диска, находить процессы и расследовать I/O-проблемы.
26 октября 202610 мин
Настроить мониторинг за 30 секунд
Надёжные уведомления о даунтаймах. Без ложных срабатываний