# jq - запросы и трансформация JSON _Команды · LinuxLab Knowledge Base_ **TL;DR:** jq - запросный язык для JSON в shell. `.field`, `.array[]`, `select(...)`, `map(...)`, пайпы внутри выражения через `|`. `-r` снимает кавычки, `-c` пакует в строку. Идеально для curl + jq + grep. ## Зачем jq HTTP API всё больше отдают JSON, ядро `kubectl`/`docker`/`gh`/`aws` тоже умеет в JSON. Парсить регулярками - больно и хрупко. jq - фактический стандарт для CLI-обработки JSON: один бинарник без зависимостей, фильтр-язык похож на XPath/jsonpath, но мощнее. Альтернатива - Python `python -c 'import json,sys;...'` - читается тяжелее в pipe. ## Базовый синтаксис ``` jq [OPTIONS] FILTER [FILE...] ``` Без файла читает stdin. Самый простой filter - `.` (identity): ```bash curl -s api.example.com/users | jq . ``` Это уже даёт цветной pretty-print - часто этого достаточно. ## Селекторы ```bash jq '.name' # поле name jq '.users[0]' # первый элемент массива jq '.users[]' # ВСЕ элементы как поток (не массив) jq '.users[].email' # поле email каждого jq '.users | length' # длина массива jq '.users | keys' # ключи объекта (или индексы массива) jq '.["weird-key"]' # ключи с дефисами/пробелами через [] jq '..|.email? // empty' # рекурсивный поиск email где угодно ``` ## select() - фильтрация ```bash # Активные пользователи jq '.users[] | select(.active == true)' # ID юзеров с >100 коммитов jq '.users[] | select(.commits > 100) | .id' # Pod'ы в статусе CrashLoopBackOff kubectl get pods -o json | jq ' .items[] | select(.status.containerStatuses[]?.state.waiting.reason == "CrashLoopBackOff") | .metadata.name' ``` `?` после поля = "если нет ключа, не падай, просто пропусти". ## Трансформация ```bash # Только имя и email каждого юзера, как массив объектов jq '.users | map({name, email})' # Из массива объектов в плоский TSV jq -r '.users[] | [.id, .name, .email] | @tsv' # Из массива в CSV с заголовком jq -r '(.users[0] | keys_unsorted), (.users[] | [.[]]) | @csv' # Группировка jq 'group_by(.team) | map({team: .[0].team, count: length})' ``` Форматтеры на конце: `@tsv`, `@csv`, `@sh` (escape для bash), `@json`, `@uri`, `@base64`, `@base64d`. ## -r и -c - **`-r` (raw output)** - снимает JSON-кавычки со строк. Без `-r`: `"foo"`, с `-r`: `foo`. Нужен когда передаёшь дальше в shell. - **`-c` (compact)** - один объект на строку без переносов. Удобно для NDJSON-логов и `xargs`. - **`-s` (slurp)** - прочитать весь stdin как один массив. По дефолту jq читает поток JSON-документов. ```bash # NDJSON: один объект на строку cat events.jsonl | jq -c 'select(.severity=="ERROR")' # Извлечь IP'ы для xargs jq -r '.hits[].ip' alerts.json | sort -u | xargs -I{} whois {} ``` ## Переменные и параметры ```bash # Передать значение из shell jq --arg user "$USER" '.users[] | select(.login == $user)' data.json # Числовое (не строкой) jq --argjson min 100 '.events[] | select(.duration_ms > $min)' data.json ``` Без `--arg` shell-подстановки в фильтре - частый источник injection-багов. Не делай `jq ".x == \"$VAR\""`, делай `jq --arg v "$VAR" '.x == $v'`. ## Reduce, foreach, paths Для агрегации: ```bash # Сумма поля size jq '[.files[].size] | add' jq '.files | reduce .[] as $f (0; . + $f.size)' # Все пути до листьев (для отладки структуры) jq '[paths(scalars)]' ``` ## jq и kubectl/docker/aws Все три CLI отдают `-o json` или `--format=json`: ```bash # Ноды и их kubelet-версия kubectl get nodes -o json | jq -r '.items[] | [.metadata.name, .status.nodeInfo.kubeletVersion] | @tsv' # Контейнеры по образу docker ps --format='{{json .}}' | jq -r 'select(.Image | contains("nginx")) | .Names' # Все S3-бакеты с тегом owner=team-x aws s3api list-buckets | jq -r '.Buckets[].Name' \ | xargs -I{} sh -c 'aws s3api get-bucket-tagging --bucket {} 2>/dev/null \ | jq -r --arg b {} ".TagSet[] | select(.Key==\"owner\" and .Value==\"team-x\") | \"\($b)\""' ``` ## Когда что-то пошло не так - **`jq: error: Cannot index ... with ...`** - применил `.field` к не-объекту (массиву, null, числу). Используй `?` или `select(type=="object")`. - **`null` в выводе вместо ошибки** - `?` глотает ошибки. Сними `?`, чтобы увидеть где сломалось. - **Кавычки в выводе мешают** - забыл `-r`. - **Переносы строк в значениях** - `-r` отдаст с физическими `\n`, может ломать pipe в `awk`. Решение: `@csv`/`@tsv` или `-c` + парсер. - **Большой файл лагает** - jq читает весь stream в память при `-s`. Без `-s` он стримит. Для гигабайтных файлов смотри **gojq** или **jaq**. - **JSON5/JSONC (с комментариями)** - jq не парсит. Сначала прогони через `yq -p json` или `jq` после удаления комментариев. ## Альтернативы - **`yq`** (Mike Farah) - jq-совместимый синтаксис для YAML/TOML/XML - **`gojq`** - Go-реализация, чуть быстрее на больших файлах - **`jaq`** - Rust, ещё быстрее, не 100% совместим с фичами - **`fx`** - интерактивный JSON-explorer (TUI) - **`jless`** - jq + less = листать большой JSON ## Команды ```bash curl -s api.github.com/repos/torvalds/linux | jq '.stargazers_count' ``` Один скаляр из ответа API - типичный pattern ```bash jq '.items[] | select(.status.phase != "Running") | .metadata.name' pods.json ``` Имена pod'ов не в Running - быстрая диагностика ```bash jq -r '.users[] | [.id, .name] | @csv' data.json > users.csv ``` JSON → CSV с правильным экранированием через @csv ```bash jq --arg id 42 '.[] | select(.user_id == ($id|tonumber))' events.json ``` Безопасная подстановка из shell + конверсия в число ```bash jq -s 'add' part1.json part2.json part3.json ``` Конкатенация массивов из нескольких файлов через -s (slurp) ```bash jq -c '.events[]' big.json | parallel -j8 'curl -X POST -d {} api/ingest' ``` Стрим NDJSON в параллельный pipeline через GNU parallel ```bash jq 'paths | join(".")' data.json | sort -u | head ``` Все пути в JSON - структурный обзор незнакомого ответа API ## См. также - [curl - HTTP-клиент из терминала](/kb/cmd-curl.md) - [awk - обработка структурированного текста по полям](/kb/cmd-awk.md) - [bash-скрипты - основы и идиомы](/kb/bash-scripting.md) - [grep - поиск строк по шаблону](/kb/cmd-grep.md) - [HTTP/1.1, HTTP/2, HTTP/3](/kb/http-protocol.md)