Форматирование JSON в Bash: jq и python3

·SRE & Shell Scripting Specialist·ПровереноErik Lindqvist·Опубликовано

Используйте бесплатный 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 таким полезным в автоматизированных пайплайнах.

Before · json
After · json
{"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

Bash
# 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 и из файла

Bash
# Передача встроенного 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

Запись форматированного вывода в файл

Bash
# Сохранение форматированного вывода (НЕ перенаправляйте обратно в тот же файл)
jq . compact.json > formatted.json

# Компактный (минифицированный) вывод — обратная операция к форматированию
jq -c . formatted.json
Примечание:jq завершается с кодом 1 при некорректном JSON, с кодом 0 при успехе и с кодом 5 при ошибке использования. Применяйте это в операторах if и в защитных конструкциях || exit 1 по всему скрипту.

Сортировка ключей и отключение цвета

Bash
# Сортировка всех ключей по алфавиту (полезно для детерминированных диффов)
jq --sort-keys . config/app-config.json

# Отключение цветного вывода при записи в лог-файл
jq --monochrome-output . response.json >> deploy.log

Справочник опций jq

Наиболее часто используемые флаги jq для форматирования и валидации:

Опция
Тип
По умолчанию
Описание
.
фильтр
Фильтр идентичности — форматирует и выводит входные данные без изменений.
--indent N
int
2
Устанавливает отступ в N пробелов (0–7). Стандартные значения — 2 или 4.
--tab
флаг
выкл
Использует символ табуляции вместо пробелов для отступа.
-c / --compact-output
флаг
выкл
Сворачивает вывод в одну строку (минификация). Отменяет форматирование.
-r / --raw-output
флаг
выкл
Выводит строки без кавычек JSON. Удобно для извлечения текстовых значений.
-e / --exit-status
флаг
выкл
Завершается с кодом 1, если вывод равен false или null. Идеально для проверок в CI.
-M / --monochrome-output
флаг
выкл
Отключает цветной вывод — полезно при перенаправлении в файлы или нетерминальные получатели.
-S / --sort-keys
флаг
выкл
Сортирует все ключи объектов по алфавиту на каждом уровне вложенности.
-n / --null-input
флаг
выкл
Не читает входные данные; используется с --arg / --argjson для построения JSON с нуля.
--arg name val
строка
Привязывает строку оболочки как именованную переменную jq ($name), доступную в фильтре.

Валидация JSON в Bash-скрипте

Валидация и форматирование — это одна и та же операция в jq: он разбирает JSON до его вывода. Перенаправляйте stdout в /dev/null, когда нужен только код выхода без форматированного вывода. Паттерн ниже переиспользуем в deploy-скриптах, pre-commit хуках и CI-пайплайнах. Когда я сталкиваюсь с незнакомым API-ответом при разборе инцидента, первое, что делаю — прогоняю его через jq: стена минифицированного JSON превращается в нечто, что реально можно читать и отлаживать.

Переиспользуемая функция валидации

Bash
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
}

Прерывание деплоя при некорректном конфиге

Bash
CONFIG="infra/k8s/app-config.json"
validate_json "$CONFIG" || { echo "Aborting deploy: invalid config" >&2; exit 1; }

Валидация всех JSON-файлов в директории

Bash
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.

Безопасное форматирование файла на месте

Bash
# Форматирование и безопасная перезапись через временный файл
tmp=$(mktemp)
jq --indent 2 . config/feature-flags.json > "$tmp" && mv "$tmp" config/feature-flags.json
echo "Formatted config/feature-flags.json"

Форматирование ответа curl API

Bash
# Форматирование статуса деплоя из API
DEPLOY_ID="dep_8f3a2b9c"
curl -s \
  -H "Authorization: Bearer $DEPLOY_API_TOKEN" \
  "https://api.deployments.internal/v1/deploys/$DEPLOY_ID" \
  | jq --indent 2 .

Форматирование и фильтрация одновременно

Bash
# Форматирование + фильтрация до ошибок из 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-конфигов

YAML
- 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-файлов

Bash
#!/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"
Примечание:Сохраните pre-commit хук в 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 из переменной

Bash
# Всегда берите "$API_RESPONSE" в кавычки — пробелы в JSON сломают подстановку без кавычек
echo "$API_RESPONSE" | jq --indent 2 .

Построение и форматирование пейлоада с помощью jq -n

Bash
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, он работает без каких-либо дополнительных зависимостей.

Bash
# Форматирование из файла
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 при интерактивном использовании.
Bash
# Валидация с кодом выхода (та же семантика, что у 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

Bash
# macOS
brew install bat

# Debian / Ubuntu (бинарник может называться batcat — при необходимости создайте алиас)
apt-get install -y bat
# alias bat=batcat   # добавьте в ~/.bashrc если нужно

# Проверка версии
bat --version  # bat 0.24.0

Просмотр JSON-файлов с подсветкой синтаксиса

Bash
# 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 в прокручиваемом пейджере

Bash
# -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

Bash
# --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 — обработка по одному объекту на строку

Bash
# 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
Bash
# Альтернатива через цикл оболочки — полезна когда нужна обработка ошибок по строкам
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.ndjson
Примечание:Переходите со стандартного jq . file.json на --stream, когда файл превышает 50–100 МБ или когда процесс выполняется внутри контейнера с ограничением памяти. Для NDJSON-пайплайнов предпочитайте jq -R 'fromjson?' циклу while read в оболочке — это значительно быстрее, поскольку не порождает подоболочку на каждую строку.

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

Перезапись исходного файла через перенаправление оболочки

Проблема: Оболочка открывает и усекает выходной файл до того, как jq читает входные данные. Если источник и назначение — один и тот же путь, jq читает пустой файл.

Решение: Сначала записывайте во временный файл через mktemp, затем атомарно заменяйте оригинал командой mv.

Before · Bash
After · Bash
jq --indent 2 . settings.json > settings.json
tmp=$(mktemp) && jq --indent 2 . settings.json > "$tmp" && mv "$tmp" settings.json
Отсутствие обработки ошибок jq в скриптах

Проблема: Без обработчика ошибок скрипт молча продолжает работу с пустым или отсутствующим форматированным файлом при некорректном JSON — последующие шаги затем завершаются с непонятными ошибками.

Решение: Добавляйте || { echo '...' >&2; exit 1; } после каждого вызова jq, который производит вывод, используемый последующими шагами.

Before · Bash
After · Bash
jq . response.json > formatted.json
jq . response.json > formatted.json || { echo "Invalid JSON in response.json" >&2; exit 1; }
Забытый флаг -s в curl

Проблема: По умолчанию curl выводит индикатор прогресса в stderr. Когда stderr объединён со stdout (например, в подоболочках или при захвате логов), текст индикатора попадает во входные данные jq и вызывает ошибку разбора.

Решение: Всегда передавайте -s (silent) в curl при передаче данных в jq. Используйте -v или --fail-with-body отдельно, если нужен диагностический вывод.

Before · Bash
After · Bash
curl https://api.payments.internal/config | jq .
curl -s https://api.payments.internal/config | jq .
Использование jq -r . в ожидании форматированного JSON

Проблема: Флаг -r / --raw-output убирает кавычки JSON со строковых значений верхнего уровня — он не форматирует объекты или массивы. Передача -r . для объекта выдаёт тот же компактный объект, а не вывод с отступами.

Решение: Используйте jq . (без флага -r) для форматирования. Оставьте -r для извлечения строковых значений, например jq -r '.version' config.json.

Before · Bash
After · Bash
jq -r . config.json
jq . config.json

jq vs python3 vs json_pp — Быстрое сравнение

Выбор инструмента зависит от того, что доступно в вашей среде и что нужно помимо базового форматирования:

Инструмент
Валидация
Подсветка
CI-совместимость
Коды выхода
Контроль отступа
Установка
jq
✅ (код 1)
✅ --indent N
brew / apt / dnf
python3 -m json.tool
✅ (строгая)
✅ (код 1)
✅ --indent N
Встроен (Python)
json_pp (Perl)
⚠️ частично
⚠️ варьируется
Встроен (Perl)
fx (Node.js)
⚠️ частично
⚠️ ограниченно
npm install -g fx
node -e JSON.parse
✅ JSON.stringify
Встроен (Node.js)

Для большинства задач bash-скриптинга и CI/CD jq является правильным выбором по умолчанию — он валидирует, форматирует, фильтрует и предоставляет надёжные коды выхода в одном бинарнике без зависимостей от рантайма. Переходите на python3 -m json.tool когда нельзя устанавливать дополнительные пакеты, но Python уже присутствует.

Часто задаваемые вопросы

Как отформатировать JSON-файл на месте в bash?

Никогда не перенаправляйте вывод jq обратно в тот же файл — оболочка усекает файл до того, как jq успевает его прочитать. Вместо этого сначала записывайте во временный файл, а затем атомарно заменяйте оригинал с помощью mv.

Bash
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.

Bash
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.

Bash
# Форматирование из файла
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.

Bash
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.

Bash
# Форматирование только блока конфигурации базы данных
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 означает ошибку использования.

Bash
# Проверка кода выхода напрямую
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 — полезны когда нужен визуальный интерфейс, ссылка для совместного использования или работа вне терминала:

Также доступно на:PythonGoJavaScript
NO
Nadia OkonkwoSRE & Shell Scripting Specialist

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.

EL
Erik LindqvistТехнический рецензент

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.