Преобразование и создание объектов JSON с jq
Изменяйте структуру данных с помощью map, to_entries и конструирования объектов, чтобы создавать новые полезные данные JSON
«Преобразование и создание объектов JSON с jq» — бесплатный урок Linux Command Line & Bash Scripting Mastery на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Linux Command Line & Bash Scripting Mastery, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Linux Command Line & Bash Scripting Mastery содержит 4 уроков всего.
Зачем преобразовывать JSON?
Необработанный JSON, полученный от API или из файлов журналов, редко имеет именно ту структуру, которая Вам нужна. Вам может прийти большой объект, из которого нужны только определённые поля, либо потребуется переименовать ключи, распрямить вложенные структуры или создать полностью новую полезную нагрузку для отправки другой службе.
jq — лёгкий и мощный обработчик JSON в командной строке, который позволяет выполнять такие преобразования в одном конвейере. В этом уроке Вы изучите три основных приёма изменения структуры данных:
- Создание объекта — построение нового объекта JSON с нуля
- map — применение преобразования к каждому элементу массива
- to_entries / from_entries — представление пар ключ-значение объекта в виде массива, чтобы их можно было фильтровать и собирать заново
Во всех примерах предполагается, что jq установлен (apt install jq / brew install jq).
Основы создания объектов
Самая фундаментальная возможность jq — создание объектов: заключение выражений в {} для построения нового объекта JSON. Вы выбираете, какие поля включить и как их назвать.
Синтаксис:
{ newKey: .existingField }— переименовать поле{ name, age }— сокращённая запись, когда новый ключ совпадает с именем поля{ total: (.price * .qty) }— вычислить значение непосредственно в выражении
Приведённый ниже фрагмент считывает JSON с данными о товаре и создаёт более компактную структуру с вычисляемым полем subtotal.
#!/usr/bin/env bash
# Object construction: pick and rename fields
product='{
"id": 42,
"name": "Widget Pro",
"price": 9.99,
"qty": 3,
"warehouse": "EU-West"
}'
echo "$product" | jq '{
productId: .id,
name,
subtotal: (.price * .qty)
}'Создание объектов из вложенных данных
В реальных данных JSON часто встречаются вложенные структуры. jq позволяет обращаться к вложенным путям внутри конструктора объекта, одновременно распрямляя структуру.
Используйте точечную запись пути в выражении значения конструктора:
{ city: .address.city }{ lat: .location.coords.lat }
Пример ниже получает глубоко вложенную запись о пользователе и создаёт плоскую сводку, подходящую для строки заголовков CSV или тела запроса к API.
#!/usr/bin/env bash
user='{
"id": "u-001",
"profile": {
"displayName": "Ada Lovelace",
"contact": { "email": "ada@example.com", "phone": "+44-700" }
},
"plan": "pro"
}'
echo "$user" | jq '{
id,
name: .profile.displayName,
email: .profile.contact.email,
plan
}'Преобразование массивов с помощью map
map(expr) — эквивалент цикла для каждого в jq: он применяет expr к каждому элементу входного массива и возвращает новый массив такой же длины.
Основные моменты:
map(expr)— это сокращённая запись[.[] | expr]- Внутреннее выражение может быть любым фильтром jq, включая создание объектов
- Объединяйте с
select(), чтобы выполнить фильтрацию перед преобразованием
Приведённый фрагмент обрабатывает список заказов, оставляя только поля, необходимые для отгрузочной ведомости.
#!/usr/bin/env bash
orders='[
{"orderId": 1, "customer": "Alice", "total": 42.50, "status": "shipped"},
{"orderId": 2, "customer": "Bob", "total": 18.00, "status": "pending"},
{"orderId": 3, "customer": "Carol", "total": 99.99, "status": "shipped"}
]'
# Produce a shipping manifest: only shipped orders, slim fields
echo "$orders" | jq '[
.[] | select(.status == "shipped") | {
id: .orderId,
recipient: .customer,
amount: .total
}
]'map с вычисляемыми полями
Внутри map можно вычислять новые значения, преобразовывать типы и объединять поля, а не только копировать их. Распространённые шаблоны:
- Интерполяция строк:
"\(.first) \(.last)" - Арифметика:
(.price * 1.2 | round)для наценки 20 % - Условные выражения:
if .score >= 90 then "A" else "B" end
Пример ниже дополняет список сотрудников вычисляемым полем fullName и меткой seniority на основе количества лет опыта.
#!/usr/bin/env bash
staff='[
{"first": "Grace", "last": "Hopper", "years": 15},
{"first": "Alan", "last": "Turing", "years": 4},
{"first": "Linus", "last": "Torvalds","years": 9}
]'
echo "$staff" | jq 'map({
fullName: "\(.first) \(.last)",
years,
seniority: (if .years >= 10 then "senior" elif .years >= 5 then "mid" else "junior" end)
})'Знакомство с to_entries
to_entries преобразует объект JSON в массив пар {key, value}. Это позволяет применять к полям объекта операции над массивами (map, select, sort), что невозможно сделать непосредственно с объектом.
Пример преобразования:
- Входные данные:
{"a": 1, "b": 2} - Результат:
[{"key": "a", "value": 1}, {"key": "b", "value": 2}]
Обратная операция — from_entries, преобразующая этот массив обратно в объект. Вместе они образуют идиому to_entries | map(...) | from_entries для преобразований на уровне объекта.
#!/usr/bin/env bash
# Demonstrate to_entries and from_entries
config='{"host": "db.local", "port": 5432, "ssl": true}'
echo "--- to_entries output ---"
echo "$config" | jq 'to_entries'
echo "--- round-trip back to object ---"
echo "$config" | jq 'to_entries | from_entries'Фильтрация ключей с помощью to_entries
Одно из наиболее практичных применений to_entries — динамическая фильтрация ключей, которые нужно оставить или удалить, на основе самого имени ключа. Создание объекта не позволяет сделать это, если имена ключей заранее неизвестны.
Шаблон:
to_entries | map(select(.key | test("regex"))) | from_entriesto_entries | map(select(.key != "secret")) | from_entries
Приведённый ниже фрагмент удаляет все ключи, начинающиеся с символа подчёркивания (внутренние или приватные поля), прежде чем передать объект конфигурации внешней службе.
#!/usr/bin/env bash
raw_config='{
"endpoint": "https://api.example.com",
"timeout": 30,
"_internalToken": "s3cr3t",
"_debugMode": true,
"retries": 3
}'
# Remove any key starting with underscore
echo "$raw_config" | jq '
to_entries
| map(select(.key | startswith("_") | not))
| from_entries
'Динамическое переименование ключей с помощью to_entries
Создание объекта переименовывает ключи, если их имена известны во время написания выражения. to_entries позволяет переименовывать ключи программно — например, преобразовывать camelCase в snake_case или добавлять префикс.
Внутри map Вы изменяете поле .key каждой записи, а затем передаёте результат в from_entries:
map(.key |= gsub("(?<=[a-z])(?=[A-Z])"; "_") | .key |= ascii_downcase)— преобразование camelCase в snake_casemap(.key |= "app_" + .)— добавление префикса к каждому ключу
Пример добавляет ко всем именам переменных окружения префикс APP_, чтобы объединить их в отдельное пространство имён перед передачей в контейнер.
#!/usr/bin/env bash
env_vars='{"host": "localhost", "port": "8080", "debug": "false"}'
# Add APP_ prefix and uppercase all keys
echo "$env_vars" | jq '
to_entries
| map({ key: ("APP_" + (.key | ascii_upcase)), value })
| from_entries
'with_entries: удобная сокращённая запись
Шаблон to_entries | map(...) | from_entries настолько распространён, что jq предоставляет для него сокращённую запись: with_entries(expr).
Она полностью эквивалентна исходному шаблону, но короче:
with_entries(.value |= . * 2)— удвоить каждое числовое значениеwith_entries(select(.value != null))— удалить ключи со значением nullwith_entries(.key |= ascii_upcase)— перевести все ключи в верхний регистр
Приведённый фрагмент удаляет все ключи, значения которых равны null или пустой строке, — это распространённый этап очистки перед отправкой запроса PATCH к REST API.
#!/usr/bin/env bash
patch_body='{
"name": "Mehmet",
"email": "",
"phone": null,
"city": "Istanbul"
}'
# Drop empty/null fields before PATCH
cleaned=$(echo "$patch_body" | jq '
with_entries(select(.value != null and .value != ""))
')
echo "Cleaned payload:"
echo "$cleaned"
# In practice you would pipe to curl:
# curl -s -X PATCH https://api.example.com/users/1 \
# -H "Content-Type: application/json" \
# -d "$cleaned"Объединение map и создания объектов в конвейере
Реальные преобразования объединяют несколько операций jq. Типичный конвейер подготовки полезной нагрузки API может выполнять следующие действия:
- Отфильтровать входной массив с помощью
map(select(...)) - Изменить структуру каждого элемента с помощью создания объекта
- Добавить вычисляемые поля
- Отсортировать результат
Пример ниже считывает список показателей серверов, оставляет только серверы с высокой загрузкой CPU и создаёт компактную полезную нагрузку оповещения, готовую для отправки методом POST веб-перехватчику.
#!/usr/bin/env bash
metrics='[
{"host": "web-01", "cpu": 23, "mem": 60, "region": "eu"},
{"host": "web-02", "cpu": 91, "mem": 88, "region": "eu"},
{"host": "db-01", "cpu": 78, "mem": 95, "region": "us"},
{"host": "db-02", "cpu": 12, "mem": 40, "region": "us"}
]'
alerts=$(echo "$metrics" | jq '[
.[] | select(.cpu > 75 or .mem > 85) | {
server: .host,
region,
severity: (if .cpu > 90 or .mem > 90 then "critical" else "warning" end),
metrics: { cpu: .cpu, mem: .mem }
}
] | sort_by(.severity)')
echo "$alerts"Создание нового объекта JSON из нескольких источников
jq может объединять входные данные и создавать объекты на основе нескольких источников JSON с помощью оператора сложения + и привязки переменных через as $var.
Полезные шаблоны:
obj1 + obj2— объединить два объекта (при конфликте ключей побеждает значение справа)--argjson— передать второй документ JSON в виде переменной$ENV— напрямую прочитать переменные окружения внутри jq
Приведённый фрагмент объединяет базовую конфигурацию с переопределениями для конкретного окружения — это распространённый шаблон управления конфигурацией приложений по принципам 12 факторов в скриптах оболочки.
#!/usr/bin/env bash
base_config='{
"logLevel": "info",
"timeout": 30,
"retries": 3,
"database": "postgres://db.local/app"
}'
env_overrides='{
"logLevel": "debug",
"database": "postgres://db.staging/app_staging"
}'
# Merge: overrides win on conflicts
merged=$(echo "$base_config" | jq --argjson overrides "$env_overrides" '. + $overrides')
echo "Merged config:"
echo "$merged"Проверка знаний: to_entries и map
У Вас есть следующий объект JSON, и Вам нужно удалить все ключи, значение которых меньше 0, создав новый объект только с неотрицательными значениями. Какое выражение jq правильно решает эту задачу?
Входные данные: {"a": 10, "b": -3, "c": 0, "d": 5}
Итоги урока: преобразование JSON с помощью jq
Вы изучили основные приёмы изменения структуры JSON с помощью jq:
- Создание объектов
{}— построение новых объектов путём выбора, переименования и вычисления полей из входных данных map(expr)— применение любого преобразования к каждому элементу массива, включая создание вложенных объектов и использованиеselect()для фильтрацииto_entries/from_entries— преобразование объекта в массив пар{key, value}, что позволяет выполнять операции над ключами и значениями как над элементами массива, а затем преобразование обратноwith_entries(expr)— краткая запись полного конвейера to_entries → map → from_entries- Объединение объектов с помощью
+и--argjsonдля полезных нагрузок из нескольких источников
Эти строительные блоки можно комбинировать: фильтровать с помощью select, изменять структуру с помощью создания объектов, дополнять вычисляемыми полями и объединять всё в одном понятном выражении jq. Освоив эти шаблоны, Вы сможете обрабатывать практически любую полезную нагрузку JSON непосредственно в оболочке, не создавая отдельный скрипт на Python или Node.
Часто задаваемые вопросы
Урок «Преобразование и создание объектов JSON с jq» бесплатный?
Да — полный текст урока «Преобразование и создание объектов JSON с jq» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Linux Command Line & Bash Scripting Mastery, подпишись на CoddyKit PRO. Курс Linux Command Line & Bash Scripting Mastery содержит 4 уроков всего.
Чему я научусь в уроке «Преобразование и создание объектов JSON с jq»?
Изменяйте структуру данных с помощью map, to_entries и конструирования объектов, чтобы создавать новые полезные данные JSON Ты практикуешь Linux Command Line & Bash Scripting Mastery с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Linux Command Line & Bash Scripting Mastery?
Предыдущий опыт не требуется. Linux Command Line & Bash Scripting Mastery на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Преобразование и создание объектов JSON с jq»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Linux Command Line & Bash Scripting Mastery?
Да. Каждый урок Linux Command Line & Bash Scripting Mastery включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Фильтрация и выборка JSON с конвейерами jq
- Преобразование и создание объектов JSON с jq
- Использование REST API с curl и jq
- Редактирование файлов конфигурации YAML с yq