Форматування 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 не є 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
# --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.