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 // b | b, если 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