Форматування 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 не є tty (наприклад, при передачі в 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.