Форматирование JSON в Bash: jq и python3
Используйте бесплатный JSON Formatter & Beautifier прямо в браузере — установка не требуется.
Попробовать JSON Formatter & Beautifier онлайн →Когда deploy-скрипт начинает обрабатывать ответы API или валидировать конфигурационные файлы в CI, умение форматировать JSON в bash становится необходимостью. Два инструмента, покрывающих 99% реальных задач, — jq и python3 -m json.tool — оба умеют надёжно форматировать JSON в bash-пайплайнах, валидировать с кодами выхода и чисто интегрироваться в CI/CD-процессы. Для разового просмотра без терминала браузерный JSON Formatter справится мгновенно. Это руководство охватывает установку jq, форматирование из пайпов и файлов, функции валидации, интеграцию в CI/CD через GitHub Actions, pre-commit хуки, heredoc-паттерны и случаи, когда стоит использовать запасной вариант из стандартной библиотеки Python.
- •
jq .форматирует И валидирует одновременно — завершается с кодом 1 при некорректном JSON - • Используйте
jq -eв CI-пайплайнах: ненулевой выход при пустом/false/null результате - •
jq . file.json > /dev/null && echo "valid"— валидация без изменения вывода - •
python3 -m json.toolработает на любой системе без дополнительной установки - • Никогда не делайте
jq . f.json > f.json— оболочка усекает исходный файл до того, как jq его прочитает
Что такое форматирование JSON в Bash?
Форматирование JSON в bash — это преобразование компактного, минифицированного JSON в читаемый вывод с отступами. Сами данные не меняются — изменяются только пробельные символы и переносы строк. В контексте скриптов это важно по двум причинам: читаемость при отладке и валидация, когда форматтер проверяет синтаксис как побочный эффект. Инструменты вроде jq полностью разбирают JSON перед переформатированием, а значит успешное форматирование является и неявной проверкой корректности. Это двойное поведение — форматирование и валидация за один шаг — и делает jq таким полезным в автоматизированных пайплайнах.
{"service":"payments-api","version":"2.4.1","database":{"host":"db-prod-01.internal","port":5432,"pool_size":20},"cache":{"enabled":true,"ttl":300}}{
"service": "payments-api",
"version": "2.4.1",
"database": {
"host": "db-prod-01.internal",
"port": 5432,
"pool_size": 20
},
"cache": {
"enabled": true,
"ttl": 300
}
}jq — форматирование JSON в Bash
jq — де-факто стандарт для обработки JSON в shell-скриптах (jq 1.6+, bash 4+). Это специализированный инструмент командной строки, способный форматировать, фильтровать, преобразовывать и валидировать JSON. Фильтр идентичности . пропускает входные данные без изменений, но с форматированием. Если jq не может разобрать входные данные, он завершается с кодом 1 — именно поэтому он идеален для скриптов: форматирование и валидация — это одна операция.
Установка jq
# macOS brew install jq # Debian / Ubuntu apt-get install -y jq # Fedora / RHEL / CentOS dnf install jq # Alpine (Docker-образы) apk add --no-cache jq # Проверка версии jq --version # jq-1.7.1
Форматирование из stdin и из файла
# Передача встроенного JSON через jq
echo '{"host":"db-prod-01.internal","port":5432}' | jq .
# Форматирование файла напрямую (вывод в stdout)
jq . config/feature-flags.json
# Форматирование с отступом 4 пробела
jq --indent 4 . config/feature-flags.json
# Форматирование с использованием табуляции вместо пробелов
jq --tab . config/feature-flags.jsonЗапись форматированного вывода в файл
# Сохранение форматированного вывода (НЕ перенаправляйте обратно в тот же файл) jq . compact.json > formatted.json # Компактный (минифицированный) вывод — обратная операция к форматированию jq -c . formatted.json
jq завершается с кодом 1 при некорректном JSON, с кодом 0 при успехе и с кодом 5 при ошибке использования. Применяйте это в операторах if и в защитных конструкциях || exit 1 по всему скрипту.Сортировка ключей и отключение цвета
# Сортировка всех ключей по алфавиту (полезно для детерминированных диффов) jq --sort-keys . config/app-config.json # Отключение цветного вывода при записи в лог-файл jq --monochrome-output . response.json >> deploy.log
Справочник опций jq
Наиболее часто используемые флаги jq для форматирования и валидации:
Валидация JSON в Bash-скрипте
Валидация и форматирование — это одна и та же операция в jq: он разбирает JSON до его вывода. Перенаправляйте stdout в /dev/null, когда нужен только код выхода без форматированного вывода. Паттерн ниже переиспользуем в deploy-скриптах, pre-commit хуках и CI-пайплайнах. Когда я сталкиваюсь с незнакомым API-ответом при разборе инцидента, первое, что делаю — прогоняю его через jq: стена минифицированного JSON превращается в нечто, что реально можно читать и отлаживать.
Переиспользуемая функция валидации
validate_json() {
local file="$1"
if jq . "$file" > /dev/null 2>&1; then
echo "✓ Valid JSON: $file"
return 0
else
echo "✗ Invalid JSON: $file" >&2
return 1
fi
}Прерывание деплоя при некорректном конфиге
CONFIG="infra/k8s/app-config.json"
validate_json "$CONFIG" || { echo "Aborting deploy: invalid config" >&2; exit 1; }Валидация всех JSON-файлов в директории
find ./config -name "*.json" | while read -r f; do jq . "$f" > /dev/null 2>&1 || echo "INVALID: $f" done
-e / --exit-status идёт дальше: он также завершается с кодом 1, когда вывод равен false или null. Используйте его для проверки истинности конкретного поля: jq -e '.feature_flags.new_checkout' config.json.Форматирование JSON из файлов и ответов API
Два основных источника JSON в shell-скриптах — файлы на диске и HTTP-ответы API через curl. Каждый из них требует немного разного подхода. Для файлов главная задача — безопасное редактирование на месте. Для ответов API ключевой момент — подавление индикатора прогресса curl, чтобы он не портил входные данные jq.
Безопасное форматирование файла на месте
# Форматирование и безопасная перезапись через временный файл tmp=$(mktemp) jq --indent 2 . config/feature-flags.json > "$tmp" && mv "$tmp" config/feature-flags.json echo "Formatted config/feature-flags.json"
Форматирование ответа curl API
# Форматирование статуса деплоя из API DEPLOY_ID="dep_8f3a2b9c" curl -s \ -H "Authorization: Bearer $DEPLOY_API_TOKEN" \ "https://api.deployments.internal/v1/deploys/$DEPLOY_ID" \ | jq --indent 2 .
Форматирование и фильтрация одновременно
# Форматирование + фильтрация до ошибок из endpoint мониторинга
curl -s "https://monitoring.internal/api/events?level=error&limit=10" \
| jq '[.events[] | {id, message, timestamp, service}]' \
|| { echo "Failed to fetch or parse events" >&2; exit 1; }Паттерн || { ... } здесь критически важен. Без него неудавшийся curl или некорректный ответ API молча проходят дальше, и следующий шаг скрипта работает с пустыми или частичными данными. Если нужно исследовать сложные вложенные ответы без предварительного написания выражений фильтра, браузерный JSON Formatter позволяет вставить сырой ответ и интерактивно навигировать по дереву.
Форматирование JSON в CI/CD-пайплайнах
В CI проверки валидности JSON наиболее важны — некорректный конфиг, дошедший до продакшена, откатывать гораздо болезненнее, чем ловить ошибку на этапе пайплайна. Большинство аналогов описывают jq для разовой работы в терминале; паттерны ниже — те, что я использую в продакшен SRE-процессах для перехвата ошибок конфигурации до того, как они достигнут deployment-слота.
GitHub Actions — валидация всех JSON-конфигов
- name: Validate JSON configs
run: |
echo "Validating JSON configuration files..."
find . -name "*.json" -not -path "*/node_modules/*" | while read -r f; do
if ! jq . "$f" > /dev/null 2>&1; then
echo "::error file=$f::Invalid JSON syntax"
exit 1
fi
done
echo "All JSON files are valid"Pre-commit хук — валидация staged JSON-файлов
#!/usr/bin/env bash
set -euo pipefail
STAGED=$(git diff --cached --name-only --diff-filter=ACM | grep '\.json$' || true)
[ -z "$STAGED" ] && exit 0
for f in $STAGED; do
jq . "$f" > /dev/null 2>&1 || { echo "Invalid JSON: $f"; exit 1; }
done
echo "JSON validation passed"scripts/validate-json.sh, сделайте его исполняемым командой chmod +x scripts/validate-json.sh, затем создайте символическую ссылку: ln -s ../../scripts/validate-json.sh .git/hooks/pre-commit.Форматирование JSON-переменных и Heredoc в Bash
Shell-скрипты часто динамически строят JSON-пейлоады — из переменных окружения, метаданных git или вычисленных значений. Самый безопасный паттерн — jq -n --arg / --argjson вместо строковой интерполяции, которая ломается, как только значение содержит кавычку или перевод строки. Всегда берите переменные в двойные кавычки при передаче в jq, чтобы избежать разбиения слов по пробелам в JSON.
Форматирование сохранённого ответа API из переменной
# Всегда берите "$API_RESPONSE" в кавычки — пробелы в JSON сломают подстановку без кавычек echo "$API_RESPONSE" | jq --indent 2 .
Построение и форматирование пейлоада с помощью jq -n
payload=$(jq -n \
--arg env "production" \
--arg version "$(git describe --tags)" \
--argjson replicas 3 \
'{environment: $env, version: $version, replicas: $replicas}')
# Просмотр построенного пейлоада
echo "$payload" | jq .
# Отправка в API
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DEPLOY_API_TOKEN" \
-d "$payload" \
"https://api.deployments.internal/v1/deploys"--arg всегда привязывает строковое значение. --argjson сначала разбирает значение как JSON, поэтому можно передавать числа, булевы значения, массивы и объекты без их экранирования внутри выражения фильтра.Форматирование JSON в Bash без установки jq
Когда jq недоступен — минимальные Docker-образы, закрытые CI-раннеры или системы, где нельзя устанавливать пакеты, — встроенный модуль json.tool из Python предоставляет те же базовые возможности. Он входит в стандартную библиотеку Python; если установлен Python 3, он работает без каких-либо дополнительных зависимостей.
# Форматирование из файла python3 -m json.tool config.json # Управление шириной отступа python3 -m json.tool --indent 2 config.json # Сортировка ключей по алфавиту python3 -m json.tool --sort-keys config.json # Форматирование из stdin (например, из curl) curl -s https://api.deployments.internal/v1/status | python3 -m json.tool
python3 -m json.tool строже, чем jq: он отвергает завершающие запятые, комментарии и расширения JSON5. Эта строгость желательна для валидации продакшен-конфигов, но может создавать трудности при работе с нестрогим JSON от сторонних инструментов. Кроме того, он не выдаёт цветной вывод, что делает терминальный просмотр менее удобным, чем у jq при интерактивном использовании.# Валидация с кодом выхода (та же семантика, что у jq)
python3 -m json.tool config.json > /dev/null && echo "valid" || echo "invalid"
# Валидация встроенной строки
echo '{"service":"payments-api","healthy":true}' | python3 -m json.tool > /dev/null
echo "Exit code: $?" # 0 = validТерминальный вывод с подсветкой синтаксиса
jq раскрашивает вывод по умолчанию — ключи синим, строки зелёным, числа белым. Когда нужна полная подсветка синтаксиса JSON в прокручиваемом пейджере или при отладке больших вложенных ответов в терминальной сессии, bat обеспечивает наилучший опыт. Оба полезны для отладки и интерактивного просмотра; ни один не стоит использовать при записи вывода в файлы или API-ответы.
Установка bat
# macOS brew install bat # Debian / Ubuntu (бинарник может называться batcat — при необходимости создайте алиас) apt-get install -y bat # alias bat=batcat # добавьте в ~/.bashrc если нужно # Проверка версии bat --version # bat 0.24.0
Просмотр JSON-файлов с подсветкой синтаксиса
# JSON с подсветкой в пейджере (нажмите q для выхода) bat config/app-config.json # Без пейджера — вывод прямо в терминал bat --paging=never config/app-config.json # Передача вывода jq через bat для цветного просмотра jq '.database' infra/app-config.json | bat --language=json --paging=never
Цветной вывод jq в прокручиваемом пейджере
# -C принудительно включает цвет даже когда stdout не является терминалом (например, при передаче в less) jq -C . logs/deploy-response.json | less -R
bat / jq -C) только для терминального просмотра и отладки. Убирайте ANSI-коды цветов перед записью в лог-файлы или передачей другим инструментам — используйте jq -M . (--monochrome-output) или bat --plain.Работа с большими JSON-файлами в Bash
Когда JSON-файл превышает 50–100 МБ, загрузка его в память в стандартном режиме jq может быть медленной или вызвать OOM на хостах с ограниченной памятью (например, Docker-контейнеры с лимитом 512 МБ). jq --stream генерирует пары путь/значение инкрементально по мере чтения, без буферизации всего документа. Для NDJSON (один JSON-объект на строку) у jq есть более эффективный нативный подход.
Потоковая обработка большого JSON-файла через jq --stream
# --stream генерирует пары [path, scalar] по мере чтения входных данных # Извлечение всех полей "status" из большого лог-архива без полной загрузки jq -c --stream 'if length == 2 and (.[0][-1] == "status") then .[1] else empty end' logs/archive-2026-03.json
NDJSON / JSON Lines — обработка по одному объекту на строку
# NDJSON: один JSON-объект на строку — часто встречается в экспортах Kafka, Fluentd и Logstash
# -R читает сырые строки; fromjson? пропускает строки, не являющиеся корректным JSON
jq -c -R 'fromjson? | {id: .request_id, status: .http_status, latency: .duration_ms}' logs/access-2026-03-13.ndjson > logs/summary.ndjson# Альтернатива через цикл оболочки — полезна когда нужна обработка ошибок по строкам
while IFS= read -r line; do
echo "$line" | jq -c '{id: .request_id, status: .http_status}' 2>/dev/null || echo "SKIP: malformed line" >&2
done < logs/access-2026-03-13.ndjsonjq . file.json на --stream, когда файл превышает 50–100 МБ или когда процесс выполняется внутри контейнера с ограничением памяти. Для NDJSON-пайплайнов предпочитайте jq -R 'fromjson?' циклу while read в оболочке — это значительно быстрее, поскольку не порождает подоболочку на каждую строку.Типичные ошибки
Проблема: Оболочка открывает и усекает выходной файл до того, как jq читает входные данные. Если источник и назначение — один и тот же путь, jq читает пустой файл.
Решение: Сначала записывайте во временный файл через mktemp, затем атомарно заменяйте оригинал командой mv.
jq --indent 2 . settings.json > settings.json
tmp=$(mktemp) && jq --indent 2 . settings.json > "$tmp" && mv "$tmp" settings.json
Проблема: Без обработчика ошибок скрипт молча продолжает работу с пустым или отсутствующим форматированным файлом при некорректном JSON — последующие шаги затем завершаются с непонятными ошибками.
Решение: Добавляйте || { echo '...' >&2; exit 1; } после каждого вызова jq, который производит вывод, используемый последующими шагами.
jq . response.json > formatted.json
jq . response.json > formatted.json || { echo "Invalid JSON in response.json" >&2; exit 1; }Проблема: По умолчанию curl выводит индикатор прогресса в stderr. Когда stderr объединён со stdout (например, в подоболочках или при захвате логов), текст индикатора попадает во входные данные jq и вызывает ошибку разбора.
Решение: Всегда передавайте -s (silent) в curl при передаче данных в jq. Используйте -v или --fail-with-body отдельно, если нужен диагностический вывод.
curl https://api.payments.internal/config | jq .
curl -s https://api.payments.internal/config | jq .
Проблема: Флаг -r / --raw-output убирает кавычки JSON со строковых значений верхнего уровня — он не форматирует объекты или массивы. Передача -r . для объекта выдаёт тот же компактный объект, а не вывод с отступами.
Решение: Используйте jq . (без флага -r) для форматирования. Оставьте -r для извлечения строковых значений, например jq -r '.version' config.json.
jq -r . config.json
jq . config.json
jq vs python3 vs json_pp — Быстрое сравнение
Выбор инструмента зависит от того, что доступно в вашей среде и что нужно помимо базового форматирования:
Для большинства задач bash-скриптинга и CI/CD jq является правильным выбором по умолчанию — он валидирует, форматирует, фильтрует и предоставляет надёжные коды выхода в одном бинарнике без зависимостей от рантайма. Переходите на python3 -m json.tool когда нельзя устанавливать дополнительные пакеты, но Python уже присутствует.
Часто задаваемые вопросы
Как отформатировать JSON-файл на месте в bash?
Никогда не перенаправляйте вывод jq обратно в тот же файл — оболочка усекает файл до того, как jq успевает его прочитать. Вместо этого сначала записывайте во временный файл, а затем атомарно заменяйте оригинал с помощью mv.
tmp=$(mktemp) jq --indent 2 . config/app-config.json > "$tmp" && mv "$tmp" config/app-config.json echo "Форматирование выполнено успешно"
Как проверить JSON в bash-скрипте и завершить работу при ошибке?
Передайте файл в jq и перенаправьте stdout в /dev/null. Используйте || для перехвата ненулевого кода выхода и прерывания скрипта. jq завершается с кодом 1 при любой ошибке разбора, что делает его надёжным инструментом для проверок в CI.
validate_json() {
local file="$1"
if jq . "$file" > /dev/null 2>&1; then
echo "✓ Valid JSON: $file"
return 0
else
echo "✗ Invalid JSON: $file" >&2
return 1
fi
}
validate_json infra/k8s/app-config.json || exit 1Как форматировать JSON в bash без установки jq?
Используйте встроенный модуль json.tool из Python 3 — он входит в стандартную библиотеку и обеспечивает корректный вывод с отступами и те же семантики кодов выхода, что и jq.
# Форматирование из файла python3 -m json.tool config.json # Форматирование из stdin (например, ответ curl) curl -s https://api.internal/status | python3 -m json.tool --indent 2
Как отформатировать ответ curl в bash?
Всегда передавайте флаг -s (silent) в curl, чтобы индикаторы прогресса не повреждали входные данные jq. Перенаправляйте stdout curl напрямую в jq.
DEPLOY_ID="dep_8f3a2b9c" curl -s \ -H "Authorization: Bearer $DEPLOY_API_TOKEN" \ "https://api.deployments.internal/v1/deploys/$DEPLOY_ID" \ | jq --indent 2 .
Как отформатировать только часть JSON-файла с помощью jq?
Используйте выражение пути jq вместо фильтра идентичности (.), чтобы извлечь и отформатировать вложенный объект или массив. Результат сам по себе является корректным JSON.
# Форматирование только блока конфигурации базы данных
jq --indent 2 '.database' infra/app-config.json
# Форматирование + фильтрация массива событий до уровня error
jq '[.events[] | select(.level == "error") | {id, message, service}]' events.jsonКакой код выхода возвращает jq при некорректном JSON?
jq завершается с кодом 1 при любой ошибке разбора, а также когда установлен флаг -e / --exit-status и вывод равен false или null. Код 0 означает, что JSON успешно разобран и вывод является истинным значением. Код 5 означает ошибку использования.
# Проверка кода выхода напрямую
echo '{"ok":true}' | jq . > /dev/null 2>&1; echo "exit: $?" # exit: 0
echo '{bad json}' | jq . > /dev/null 2>&1; echo "exit: $?" # exit: 1
# Флаг -e: выход 1 если вывод false/null
echo 'null' | jq -e . > /dev/null 2>&1; echo "exit: $?" # exit: 1Связанные инструменты
Браузерные альтернативы и дополнения к форматированию JSON в bash — полезны когда нужен визуальный интерфейс, ссылка для совместного использования или работа вне терминала:
Nadia is a site reliability engineer who lives in the terminal. She writes Bash scripts that process logs, transform data, and orchestrate infrastructure across fleets of servers. She is a heavy user of jq, awk, and sed and writes about shell one-liners, text processing pipelines, data serialisation from the command line, and the practical Bash patterns that SREs reach for when speed matters more than elegance.
Erik is a DevOps engineer who has spent years writing and maintaining the shell scripts that hold CI/CD pipelines together. He writes about Bash best practices, portable POSIX shell, encoding and decoding in shell scripts, secret management from the command line, and the patterns that separate reliable automation scripts from brittle ones. He is a strong believer in making shell scripts readable and testable with tools like bats-core.