← Весь справочник

jq

Разбор и преобразование JSON — выборка полей, select, map, строки, даты, вывод в CSV/TSV

jq читает JSON, пропускает его через фильтр и печатает результат. Фильтр — маленькая программа: . — весь документ, .поле — значение поля, | передаёт результат дальше, как в оболочке. Фильтр может выдать ноль, одно или много значений — каждое печатается отдельно.

Синтаксис

jq [опции] 'фильтр' [файл…]
jq [опции] -f программа.jq [файл…]

Без файла читает stdin. Фильтр всегда бери в одинарные кавычки, иначе оболочка испортит $, | и кавычки внутри.

Опции вывода

ОпцияЧто делает
-rстроки без кавычек и экранирования — для дальнейшей обработки в оболочке
-jкак -r, но без перевода строки после каждого значения
-cкомпактно: каждый результат в одну строку
-Sотсортировать ключи объектов
--tab / --indent Nотступ табуляцией / N пробелов
-aне-ASCII символы как \uXXXX
-C / -Mпринудительно включить / выключить цвет
-eкод выхода по результату: 1, если последнее значение null или false; 4, если результата нет

Опции ввода и переменные

ОпцияЧто делает
-nне читать вход; данные создаются в фильтре или читаются через input/inputs
-sсобрать все входные документы в один массив
-Rчитать строки как текст, а не JSON (с -s — весь вход одной строкой)
-f файлвзять фильтр из файла
--arg имя значениепередать строку как $имя
--argjson имя JSONпередать число, массив или объект как $имя
--slurpfile имя файлJSON из файла — массивом в $имя
--rawfile имя файлсодержимое файла строкой в $имя
--args / --jsonargsостальные аргументы — строками / JSON-значениями в $ARGS.positional

Переменные окружения доступны как $ENV.ИМЯ или env.ИМЯ.

Пути и выборка

ФильтрЧто делает
.весь вход
.a.b, .a["b"], ."a-b"поле; кавычки — для имён с дефисом, пробелом, точкой
.[0], .[-1], .[2:4]элемент по индексу, последний, срез
.[]все элементы массива (или значения объекта) по одному
.a?, .[]?то же, но без ошибки, если тип не подходит
..рекурсивно все значения на любой глубине
f, gоба результата подряд
f | gрезультат f на вход g
[ f ]собрать все результаты f в массив
{a: f, b}собрать объект; {b} = {b: .b}; {(.k): .v} — вычисляемый ключ

Операторы и конструкции

КонструкцияЧто делает
+ - * / %арифметика; + также склеивает строки, массивы и объекты
== != < <= > >=сравнения
and, or, notлогика: select(.a and (.b | not))
a // bb, если a — null, false или ничего
if … then … elif … else … endусловие
try f catch gперехват ошибки; f? — молча пропустить ошибку
. as $x | …сохранить значение в переменную
reduce .[] as $x (0; . + $x)свёртка: накопить результат по элементам
def f: …;своя функция
.a = v, .a |= f, .a += vприсвоить, обновить через фильтр, прибавить
del(.a)удалить поле или элементы
"\(.name): \(.age)"подстановка значений в строку

Встроенные функции

ФункцииЧто делают
length, keys, keys_unsorted, has("k"), typeдлина (строки, массива, объекта), ключи, наличие ключа, тип
select(усл), empty, error("msg")фильтрация; «ничего»; ошибка
map(f), map_values(f)применить к каждому элементу массива / значению объекта
add, any(усл), all(усл), min, max, min_by(f), max_by(f)сумма/склейка, хоть один / все, минимум, максимум
sort, sort_by(f), group_by(f), unique, unique_by(f), reverseсортировка, группировка, уникальные
first, last, first(f), limit(n; f), range(n)первые/последние значения, генерация чисел
flatten, index(x), contains(x), inside(x)расплющить, найти позицию, проверить вхождение
to_entries, from_entries, with_entries(f)объект ↔ массив {key, value}; переименовать или отфильтровать ключи
paths, path(f), getpath(p), setpath(p; v)работа с путями внутри документа
tostring, tonumber, tojson, fromjsonпреобразование типов, JSON внутри строки
split(s), join(s), ascii_downcase, ascii_upcaseстроки
startswith, endswith, ltrimstr, rtrimstrпрефиксы и суффиксы
test(re), match(re), capture(re), sub(re; s), gsub(re; s)регулярные выражения (флаг "i" вторым аргументом — без учёта регистра)
now, todate, fromdate, strftime(fmt)время: Unix-время ↔ ISO 8601
input, inputsследующий входной документ / все оставшиеся (вместе с -n)
@csv, @tsv, @sh, @base64, @base64d, @uri, @html, @jsonформатировать значение как CSV, TSV, аргументы оболочки, Base64…

Примеры

cat > users.json <<'EOF'
{"users":[
  {"name":"anna","age":31,"roles":["admin","dev"],"active":true},
  {"name":"boris","age":25,"roles":["dev"],"active":false}
]}
EOF

# красиво отформатировать и заодно проверить, что JSON валиден
jq . users.json

# имена построчно, без кавычек
jq -r '.users[].name' users.json

# только активные пользователи старше 30
jq -r '.users[] | select(.active and .age > 30) | .name' users.json

# у кого есть роль admin
jq -r '.users[] | select(.roles | index("admin")) | .name' users.json

# новый объект на каждого — по строке на запись
jq -c '.users[] | {name, roles: (.roles | length)}' users.json

# сколько записей и средний возраст
jq '.users | length' users.json
jq '[.users[].age] | add / length' users.json

# сколько пользователей в каждой группе
jq -c '.users | group_by(.active) | map({active: .[0].active, count: length})' users.json

# в TSV для sort, awk, cut
jq -r '.users[] | [.name, .age] | @tsv' users.json

# подставить значение из переменной оболочки безопасно
jq --arg n "$USER" '.owner = $n' users.json

# объединить несколько JSON-файлов в массив
jq -s '.' a.json b.json

# строки текста → JSON-массив
printf 'one\ntwo\n' | jq -R . | jq -s -c .

# Unix-время в дату
echo '{"ts":1700000000}' | jq -r '.ts | todate'

# «изменить файл»: jq не умеет -i, пишем во временный и подменяем
jq '.users[1].active = true' users.json > users.tmp && mv users.tmp users.json

Подводные камни

  • -i нет. jq '…' f.json > f.json обнулит файл до того, как jq его прочитает. Пиши во временный файл и делай mv.
  • Без -r строки остаются в кавычках: "anna". В переменную оболочки или в цикл обычно нужно -r.
  • Несуществующее поле — это null, а не ошибка. Опечатка в имени тихо даёт null. Добавь -e, чтобы получить ненулевой код выхода.
  • // срабатывает и на false. .active // true превратит настоящее false в true. Для булевых полей проверяй явно: if .active == null then true else .active end.
  • Поле с дефисом: .a-b jq понимает как «.a минус b». Пиши ."a-b" или .["a-b"].
  • | слабее запятой. .a | length, .b — это .a | (length, .b), и .b ищется внутри .a. Ставь скобки: (.a | length), .b.
  • Не склеивай фильтр со значениями из оболочки. jq ".name == \"$x\"" ломается на кавычках в $x. Передавай данные через --arg / --argjson.
  • --arg всегда даёт строку. --arg n 5 и сравнение .age > $n сравнит число со строкой. Для чисел — --argjson.
  • .users[] выдаёт несколько отдельных значений, а не массив. Чтобы снова получить массив, оберни в [ … ] или используй map.
  • Ошибка разбора (parse error: Invalid numeric literal) значит, что на вход пришёл не JSON: HTML-страница ошибки, пустой ответ, лишний текст. Проверь вход без jq.

См. также

yq · curl · xmllint · sort · awk