Spec-Zone.ru › jq

jq 1.7 Руководство

Руководство для версии для разработчиков jq можно найти здесь.

Программа jq — это «фильтр»: она принимает входные данные и производит выходные. Существует множество встроенных фильтров для извлечения определённого поля объекта, преобразования числа в строку или выполнения других стандартных задач.

Фильтры можно комбинировать различными способами — вы можете передать результат одного фильтра в другой фильтр или собрать результат фильтра в массив.

Некоторые фильтры производят несколько результатов, например, есть фильтр, который производит все элементы входного массива. Передача этого фильтра во второй фильтр запускает второй фильтр для каждого элемента массива. В целом, то, что в других языках делается с циклами и итерациями, в jq делается путём объединения фильтров.

Важно помнить, что каждый фильтр имеет вход и выход. Даже литералы, такие как «hello» или 42, являются фильтрами — они принимают вход, но всегда производят тот же самый литерал в качестве вывода. Операции, объединяющие два фильтра, например, сложение, обычно подают один и тот же вход обоим и объединяют результаты. Таким образом, вы можете реализовать фильтр усреднения как add / length — подав входной массив как в фильтр add, так и в фильтр length, а затем выполнив деление.

Но это опережает нас. :) Давайте начнём с чего-то более простого:

Вызов jq

Фильтры jq работают со потоком JSON-данных. Ввод для jq парсится как последовательность разделенных пробелами JSON-значений, которые передаются через заданный фильтр по одному. Результат(ы) фильтра записываются в стандартный вывод, как последовательность JSON-данных, разделенных символами новой строки.

Самый простой и распространенный фильтр (или программа jq) — ., который является оператором идентичности, копируя входные данные процессора jq в поток вывода. Поскольку поведение по умолчанию процессора jq заключается в чтении JSON-текстов из входного потока и форматировании вывода, программа . в основном используется для валидации и форматирования входных данных. Язык программирования jq довольно богат и позволяет гораздо больше, чем просто валидация и форматирование.

Примечание: важно учитывать правила цитирования оболочки. Как общее правило, лучше всегда заключать программу jq в кавычки (одинарные кавычки в оболочках Unix), так как слишком много символов со специальным значением для jq также являются метасимволами оболочки. Например, jq "foo" потерпит неудачу в большинстве оболочек Unix, потому что это будет то же самое, что и jq foo, что обычно закончится неудачей, потому что foo is not defined. При использовании командной оболочки Windows (cmd.exe) лучше использовать двойные кавычки вокруг программы jq при вводе в командной строке (вместо параметра -f program-file), но тогда двойные кавычки в программе jq необходимо экранировать обратной косой чертой. При использовании Powershell (powershell.exe) или Powershell Core (pwsh/pwsh.exe) используйте одинарные кавычки вокруг программы jq и экранируйте обратной косой чертой двойные кавычки (\") внутри программы jq.

  • Оболочки Unix: jq '.["foo"]'
  • Powershell: jq '.[\"foo\"]'
  • Командная оболочка Windows: jq ".[\"foo\"]"

Примечание: jq позволяет определять пользовательские функции, но каждая программа jq должна иметь выражение верхнего уровня.

Вы можете повлиять на то, как jq читает и записывает свои входные и выходные данные, используя некоторые параметры командной строки:

  • --null-input / -n:

Не читать никакой ввод. Вместо этого фильтр выполняется один раз с использованием null в качестве входных данных. Это полезно при использовании jq как простого калькулятора или для построения JSON-данных с нуля.

  • --raw-input / -R:

Не парсить ввод как JSON. Вместо этого каждая строка текста передается фильтру как строка. Если объединить с --slurp, то весь ввод передается фильтру как одна длинная строка.

  • --slurp / -s:

Вместо выполнения фильтра для каждого JSON-объекта во входном потоке, прочитать весь входной поток в большой массив и выполнить фильтр только один раз.

  • --compact-output / -c:

По умолчанию jq форматирует JSON-вывод. Использование этого параметра приведет к более компактному выводу, помещая каждый JSON-объект на отдельной строке.

  • --raw-output / -r:

С этим параметром, если результатом фильтра является строка, она будет записана непосредственно в стандартный вывод, а не форматироваться как JSON-строка с кавычками. Это может быть полезно для взаимодействия фильтров jq с не-JSON-системами.

  • --raw-output0:

Как -r, но jq выведет NUL вместо новой строки после каждого результата. Это может быть полезно, когда выводимые значения могут содержать новые строки. Когда выводимое значение содержит NUL, jq завершается с ненулевым кодом.

  • --join-output / -j:

Как -r, но jq не будет выводить новую строку после каждого результата.

  • --ascii-output / -a:

jq обычно выводит не-ASCII Unicode-символы как UTF-8, даже если входные данные указали их как последовательности экранирования (например, «\u03bc»). Используя этот параметр, вы можете заставить jq производить вывод только ASCII, заменяя каждый не-ASCII символ эквивалентной последовательностью экранирования.

  • --sort-keys / -S:

Вывести поля каждого объекта с ключами в отсортированном порядке.

  • --color-output / -C и --monochrome-output / -M:

По умолчанию jq выводит цветной JSON, если вывод направлен в терминал. Вы можете заставить его производить цветной вывод даже при записи в конвейп или файл, используя -C, и отключить цвет с помощью -M. Когда переменная окружения NO_COLOR не пуста, jq по умолчанию отключает цветной вывод, но вы можете включить его, используя -C.

Цвета можно настроить с помощью переменной окружения JQ_COLORS (см. ниже).

  • --tab:

Использовать табуляцию для каждого уровня отступа вместо двух пробелов.

  • --indent n:

Использовать заданное количество пробелов (не более 7) для отступов.

  • --unbuffered:

Очистить выходные данные после печати каждого JSON-объекта (полезно, если вы передаете медленный источник данных в jq и направляете вывод jq в другое место).

  • --stream:

Парсить ввод в потоковом режиме, выводить массивы пути и значений листа (скаляры и пустые массивы или пустые объекты). Например, "a" превращается в [[],"a"], а [[],"a",["b"]] превращается в [[0],[]], [[1],"a"], и [[2,0],"b"].

Это полезно для обработки очень больших входов. Используйте это в сочетании с фильтрацией и синтаксисом reduce и foreach для постепенного уменьшения больших входов.

  • --stream-errors:

Как --stream, но невалидные JSON-входы дают значения массива, где первый элемент — ошибка, а второй — путь. Например, ["a",n] производит ["Invalid literal at line 1, column 7",[1]].

Подразумевает --stream. Невалидные JSON-входы не генерируют значений ошибок, когда --stream без --stream-errors.

  • --seq:

Использовать схему MIME application/json-seq для разделения JSON-текстов во входных и выходных данных jq. Это означает, что перед каждым значением на выходе печатается символ ASCII RS (разделитель записей), а после каждого результата печатается символ ASCII LF (перевод строки). Входные JSON-тексты, которые не удается разобрать, игнорируются (но об этом сообщается), отбрасывая весь последующий ввод до следующего RS. Этот режим также анализирует вывод jq без параметра --seq.

  • -f filename / --from-file filename:

Читать фильтр из файла, а не из командной строки, как параметр -f утилиты awk. Вы также можете использовать '#' для создания комментариев.

  • -L directory:

Добавить directory в список поиска модулей. Если этот параметр используется, то используется встроенный список поиска.

  • --arg name value:

Этот параметр передает значение в программу jq как предопределенную переменную. Если вы запустите jq с --arg foo bar, то $foo будет доступен в программе и иметь значение "bar". Обратите внимание, что value будет обрабатываться как строка, поэтому --arg foo 123 свяжет $foo со значением "123".

Именованные аргументы также доступны программе jq как $ARGS.named.

  • --argjson name JSON-text:

Этот параметр передает закодированное в JSON значение в программу jq как предопределенную переменную. Если вы запустите jq с --argjson foo 123, то $foo будет доступен в программе и иметь значение 123.

  • --slurpfile variable-name filename:

Этот параметр считывает все JSON-тексты в указанном файле и связывает массив обработанных JSON-значений с заданной глобальной переменной. Если вы запустите jq с --slurpfile foo bar, то $foo будет доступен в программе и содержать массив, элементы которого соответствуют текстам в файле под названием bar.

  • --rawfile variable-name filename:

Этот параметр считывает указанный файл и связывает его содержимое с заданной глобальной переменной. Если вы запустите jq с --rawfile foo bar, то $foo будет доступен в программе и содержать строку, чье содержимое соответствует текстам в файле под названием bar.

  • --args:

Остальные аргументы являются позиционными строковыми аргументами. Они доступны в программе jq как $ARGS.positional[].

  • --jsonargs:

Остальные аргументы являются позиционными аргументами JSON-текста. Они доступны в программе jq как $ARGS.positional[].

  • --exit-status / -e:

Устанавливает код завершения jq в 0, если последнее значение вывода не было ни false, ни null, в 1, если последнее значение вывода было либо false, либо null, или 4, если никогда не был получен действительный результат. Обычно jq завершается с кодом 2, если возникла проблема с использованием или системная ошибка, с кодом 3, если возникла ошибка компиляции jq, или 0, если программа jq выполнилась.

Другой способ установить код завершения — с помощью встроенной функции halt_error.

  • --binary / -b:

Пользователям Windows, использующим WSL, MSYS2 или Cygwin, следует использовать этот параметр при использовании локального jq.exe, иначе jq будет преобразовывать новые строки (LF) в возвраты каретки (CRLF).

  • --version / -V:

Вывести версию jq и завершиться с кодом 0.

  • --build-configuration:

Вывести конфигурацию сборки jq и завершиться с кодом 0. Этот вывод не имеет поддерживаемого формата или структуры и может измениться без предварительного уведомления в будущих выпусках.

  • --help / -h:

Вывести справку jq и завершиться с кодом 0.

  • --:

Останавливает обработку аргументов. Остальные аргументы являются позиционными, либо строками, JSON-текстами или именами файлов ввода, в зависимости от того, были ли указаны --args или --jsonargs.

  • --run-tests [filename]:

Выполняет тесты в указанном файле или стандартном вводе. Это должен быть последний параметр, и он не учитывает все предыдущие параметры. Вход состоит из строк комментариев, пустых строк и строк программы, за которыми следует одна строка ввода, столько строк вывода, сколько ожидается (по одной на вывод), и завершающая пустая строка. Тесты на ошибку компиляции начинаются со строки, содержащей только %%FAIL, затем со строки, содержащей программу для компиляции, затем со строки, содержащей сообщение об ошибке для сравнения с фактическим.

Будьте осторожны, так как этот параметр может меняться несовместимо.

Базовые фильтры

Identity: .

Абсолютно простейший фильтр — это . . Этот фильтр принимает свой вход и выдает то же самое значение на выходе. То есть это оператор тождества.

Поскольку jq по умолчанию форматирует весь вывод, тривиальная программа, состоящая только из ., может использоваться для форматирования JSON-вывода, например, из curl.

Хотя фильтр тождества никогда не изменяет значение своего входа, обработка jq иногда может создавать видимость того, что он это делает. Например, используя текущую реализацию jq, мы увидим, что выражение:

1E1234567890 | .

выдает 1.7976931348623157e+308 по крайней мере на одной платформе. Это происходит потому, что в процессе анализа числа эта конкретная версия jq преобразует его в представление с двойной точностью IEEE754, теряя точность.

Способ обработки чисел в jq со временем менялся, и дальнейшие изменения, вероятно, находятся в рамках параметров, установленных соответствующими стандартами JSON. Поэтому следующие замечания предлагаются с пониманием того, что они предназначены для описания текущей версии jq и не должны интерпретироваться как предписывающие:

(1) Любая арифметическая операция над числом, которое еще не было преобразовано в представление с двойной точностью IEEE754, вызовет преобразование в представление IEEE754.

(2) jq будет пытаться сохранить исходную десятичную точность числовых литералов, но в выражениях типа 1E1234567890, точность будет потеряна, если показатель степени слишком велик.

(3) В программах jq ведущий знак минус вызовет преобразование числа в представление IEEE754.

(4) Сравнения выполняются с использованием не усеченного представления чисел с большой точностью, если оно доступно, как показано в одном из следующих примеров.

Команда jq '.'
Вход "Hello, world!"
Вывод "Hello, world!"
Запустить
Команда jq '.'
Вход 0.12345678901234567890123456789
Вывод 0.12345678901234567890123456789
Запустить
Команда jq '[., tojson]'
Вход 12345678909876543212345
Вывод [12345678909876543212345,"12345678909876543212345"]
Запустить
Команда jq '. < 0.12345678901234567890123456788'
Вход 0.12345678901234567890123456789
Вывод false
Запустить
Команда jq 'map([., . == 1]) | tojson'
Вход [1, 1.000, 1.0, 100e-2]
Вывод "[[1,true],[1.000,true],[1.0,true],[1.00,true]]"
Запустить
Команда jq '. as $big | [$big, $big + 1] | map(. > 10000000000000000000000000000000)'
Вход 10000000000000000000000000000001
Вывод [true, false]
Запустить

Индекс идентификатора объекта: .foo, .foo.bar

Простейший полезный фильтр имеет вид .foo. При получении в качестве входных данных объекта JSON (также известного как словарь или хеш), .foo выдает значение по ключу "foo", если ключ присутствует, или null в противном случае.

Фильтр вида .foo.bar эквивалентен .foo | .bar.

Синтаксис .foo работает только для простых ключей, похожих на идентификаторы, то есть ключей, которые состоят только из буквенно-цифровых символов и символа подчеркивания, и которые не начинаются с цифры.

Если ключ содержит специальные символы или начинается с цифры, необходимо заключить его в двойные кавычки, например: ."foo$", иначе .["foo$"].

Например, .["foo::bar"] и .["foo.bar"] работают, а .foo::bar — нет.

Команда jq '.foo'
Вход {"foo": 42, "bar": "less interesting data"}
Вывод 42
Запустить
Команда jq '.foo'
Вход {"notfoo": true, "alsonotfoo": false}
Вывод null
Запустить
Команда jq '.["foo"]'
Вход {"foo": 42}
Вывод 42
Запустить

Необязательный индекс идентификатора объекта: .foo?

То же самое, что и .foo, но не выдает ошибку, когда . не является объектом.

Команда jq '.foo?'
Вход {"foo": 42, "bar": "less interesting data"}
Вывод 42
Запустить
Команда jq '.foo?'
Вход {"notfoo": true, "alsonotfoo": false}
Вывод null
Запустить
Команда jq '.["foo"]?'
Вход {"foo": 42}
Вывод 42
Запустить
Команда jq '[.foo?]'
Вход [1,2]
Вывод []
Запустить

Индекс объекта: .[<string>]

Вы также можете искать поля объекта, используя синтаксис, подобный .["foo"] (.foo выше является сокращенной версией этого, но только для строк, подобных идентификаторам).

Индекс массива: .[<number>]

Когда значение индекса является целым числом, .[<number>] может индексировать массивы. Массивы нумеруются с нуля, поэтому .[2] возвращает третий элемент.

Допускаются отрицательные индексы, при этом -1 относится к последнему элементу, -2 — к предпоследнему и так далее.

Команда jq '.[0]'
Входные данные [{"name":"JSON", "good":true}, {"name":"XML", "good":false}]
Результат {"name":"JSON", "good":true}
Запуск
Команда jq '.[2]'
Входные данные [{"name":"JSON", "good":true}, {"name":"XML", "good":false}]
Результат null
Запуск
Команда jq '.[-2]'
Входные данные [1,2,3]
Результат 2
Запуск

Вырезка массива/строки: .[<number>:<number>]

Синтаксис .[<number>:<number>] может использоваться для возвращения подмассива массива или подстроки строки. Массив, возвращаемый .[10:15], будет иметь длину 5 и будет содержать элементы с индекса 10 (включительно) до индекса 15 (исключительно). Любой из индексов может быть отрицательным (в этом случае он отсчитывается от конца массива) или пропущен (в этом случае он относится к началу или концу массива). Индексы нумеруются с нуля.

Команда jq '.[2:4]'
Входные данные ["a","b","c","d","e"]
Результат ["c", "d"]
Запуск
Команда jq '.[2:4]'
Входные данные "abcdefghi"
Результат "cd"
Запуск
Команда jq '.[:3]'
Входные данные ["a","b","c","d","e"]
Результат ["a", "b", "c"]
Запуск
Команда jq '.[-2:]'
Входные данные ["a","b","c","d","e"]
Результат ["d", "e"]
Запуск

Итератор значений массива/объекта: .[]

Если вы используете синтаксис .[index], но полностью опускаете индекс, он вернет все элементы массива. Выполнение .[] с входными данными [1,2,3] приведет к тому, что числа будут выведены как три отдельных результата, а не как один массив. Фильтр вида .foo[] эквивалентен .foo | .[].

Вы также можете использовать это для объекта, и он вернет все значения объекта.

Обратите внимание, что оператор итератора является генератором значений.

Команда jq '.[]'
Входные данные [{"name":"JSON", "good":true}, {"name":"XML", "good":false}]
Результат {"name":"JSON", "good":true}
{"name":"XML", "good":false}
Запуск
Команда jq '.[]'
Входные данные []
Результат none
Запуск
Команда jq '.foo[]'
Входные данные {"foo":[1,2,3]}
Результат 1
2
3
Запуск
Команда jq '.[]'
Входные данные {"a": 1, "b": 1}
Результат 1
1
Запуск

.[]?

Как .[], но никаких ошибок не будет выведено, если . не является массивом или объектом. Фильтр вида .foo[]? эквивалентен .foo | .[]?.

Запятая: ,

Если два фильтра разделены запятой, то на оба подаются одни и те же входные данные, и потоки выходных значений двух фильтров конкатенируются по порядку: сначала все выходные данные, полученные левым выражением, а затем все выходные данные, полученные правым. Например, фильтр .foo, .bar выдает поля "foo" и "bar" как отдельные результаты.

Оператор , — это один из способов построения генераторов.

Команда jq '.foo, .bar'
Входные данные {"foo": 42, "bar": "something else", "baz": true}
Результат 42
"something else"
Запуск
Команда jq '.user, .projects[]'
Входные данные {"user":"stedolan", "projects": ["jq", "wikiflow"]}
Результат "stedolan"
"jq"
"wikiflow"
Запуск
Команда jq '.[4,2]'
Входные данные ["a","b","c","d","e"]
Результат "e"
"c"
Запуск

Труба: |

Оператор | объединяет два фильтра, передавая вывод левого фильтра на вход правого. Он похож на конвейер в оболочке Unix, если вам знакома эта концепция.

Если левый фильтр производит несколько результатов, правый фильтр будет выполняться для каждого из этих результатов. Таким образом, выражение .[] | .foo извлекает поле "foo" каждого элемента входного массива. Это декартово произведение, что может быть неожиданным.

Обратите внимание, что .a.b.c эквивалентно .a | .b | .c.

Также обратите внимание, что . — это значение входных данных на определенной стадии "конвейера", конкретно: там, где появляется выражение .. Таким образом, .a | . | .b эквивалентно .a.b, так как . в середине относится к значению, которое вывело .a.

Команда jq '.[] | .name'
Входные данные [{"name":"JSON", "good":true}, {"name":"XML", "good":false}]
Вывод "JSON"
"XML"
Запустить

Скобки

Скобки работают как операторы группировки, как и в любом типичном языке программирования.

Команда jq '(. + 2) * 5'
Входные данные 1
Вывод 15
Запустить

Типы и значения

jq поддерживает тот же набор типов данных, что и JSON: числа, строки, булевы значения, массивы, объекты (которые в JSON называются хэшами с только строковыми ключами) и «null».

Булевы значения, null, строки и числа записываются так же, как и в JSON. Как и всё остальное в jq, эти простые значения принимают входные данные и производят выходные — 42 — это допустимое выражение jq, которое принимает входные данные, игнорирует их и возвращает 42 вместо этого.

Числа в jq внутренне представляются своим приближением двойной точности IEEE754. Любая арифметическая операция с числами, будь то литералы или результаты предыдущих фильтров, даст результат с плавающей точкой двойной точности.

Однако при разборе литерала jq сохранит исходную строку литерала. Если к этому значению не применить преобразования, оно будет передано в выходные данные в исходной форме, даже если преобразование в двойное значение приведет к потере данных.

Создание массивов: []

Как и в JSON, [] используется для создания массивов, как в [1,2,3]. Элементы массивов могут быть любыми выражениями jq, включая конвейер. Все результаты, произведённые всеми выражениями, собираются в один большой массив. Можно использовать его для создания массива из известного количества значений (как в [.foo, .bar, .baz]) или для «собирания» всех результатов фильтра в массив (как в [.items[].name])

Поняв оператор «,» можно взглянуть на синтаксис массивов jq под другим углом: выражение [1,2,3] не использует встроенный синтаксис для массивов, разделенных запятыми, а вместо этого применяет оператор [] (собрать результаты) к выражению 1,2,3 (которое производит три разных результата).

Если у вас есть фильтр X, который производит четыре результата, то выражение [X] произведёт один результат — массив из четырёх элементов.

Команда jq '[.user, .projects[]]'
Входные данные {"user":"stedolan", "projects": ["jq", "wikiflow"]}
Вывод ["stedolan", "jq", "wikiflow"]
Запустить
Команда jq '[ .[] | . * 2]'
Входные данные [1, 2, 3]
Вывод [2, 4, 6]
Запустить

Создание объектов: {}

Как и в JSON, {} используется для создания объектов (также известных как словари или хэши), как в {"a": 42, "b": 17}.

Если ключи похожи на идентификаторы, кавычки можно опустить, как в {a:42, b:17}. Ссылок на переменные в качестве выражений ключей используют значение переменной как ключ. Выражения ключей, отличные от константных литералов, идентификаторов или ссылок на переменные, необходимо заключать в скобки, например, {("a"+"b"):59}.

Значение может быть любым выражением (хотя, возможно, его нужно заключить в скобки, если, например, оно содержит двоеточия), которое применяется к входным данным выражения {} (помните, у всех фильтров есть вход и выход).

{foo: .bar}

произведёт JSON-объект {"foo": 42} при вводе JSON-объекта {"bar":42, "baz":43}. Можно использовать это для выбора определённых полей объекта: если входной объект содержит поля "user", "title", "id" и "content", и вам нужны только "user" и "title", можно написать

{user: .user, title: .title}

Так как это очень распространённо, существует сокращённый синтаксис: {user, title}.

Если одно из выражений производит несколько результатов, будет произведено несколько словарей. Если у входных

{"user":"stedolan","titles":["JQ Primer", "More JQ"]}

то выражение

{user, title: .titles[]}

произведёт два вывода:

{"user":"stedolan", "title": "JQ Primer"}
{"user":"stedolan", "title": "More JQ"}

Заключение ключа в скобки означает, что он будет оценён как выражение. С тем же входным объектом, что и выше,

{(.user): .titles}

производит

{"stedolan": ["JQ Primer", "More JQ"]}

Ссылок на переменные в качестве ключей используют значение переменной как ключ. Без значения имя переменной становится ключом, а её значение — значением,

"f o o" as $foo | "b a r" as $bar | {$foo, $bar:$foo}

производит

{"foo":"f o o","b a r":"f o o"}

Рекурсивный спуск: ..

Рекурсивно спускается ., производя каждое значение. Это то же самое, что и встроенная функция recurse без аргументов (см. ниже). Это призвано имитировать оператор XPath //. Обратите внимание, что ..a не работает; используйте .. | .a вместо него. В примере ниже мы используем .. | .a? для поиска всех значений ключей "a" в любом объекте, найденном "ниже" ..

Это особенно полезно в сочетании с path(EXP) (также см. ниже) и оператором ?.

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

Некоторые операторы jq (например, +) выполняют разные действия в зависимости от типа своих аргументов (массивы, числа и т.д.). Однако jq никогда не выполняет неявное преобразование типов. Если вы попытаетесь добавить строку к объекту, вы получите сообщение об ошибке и никакого результата.

Обратите внимание, что все числа преобразуются в представление с плавающей точкой двойной точности IEEE754. Арифметические и логические операторы работают с этими преобразованными числами с плавающей точкой двойной точности. Результаты всех таких операций также ограничены двойной точностью.

Единственным исключением из этого поведения чисел является снимок исходного числового литерала. Если число, первоначально предоставленное как литерал, никогда не изменяется до конца программы, то оно выводится в исходном виде литерала. Это также включает в себя случаи, когда исходный литерал будет усечен при преобразовании в число с плавающей точкой двойной точности IEEE754.

Сложение: +

Оператор + принимает два фильтра, применяет их оба к одному и тому же входному значению и складывает результаты. То, что означает «сложение», зависит от типов, участвующих в операции:

  • Числа складываются с помощью обычной арифметики.

  • Массивы складываются путем конкатенации в более крупный массив.

  • Строки складываются путем объединения в более длинную строку.

  • Объекты складываются путем слияния, то есть вставки всех пар ключ-значение из обоих объектов в один объединенный объект. Если оба объекта содержат значение для одного и того же ключа, выигрывает объект справа от +. (Для рекурсивного слияния используйте оператор *).

null можно добавить к любому значению, и он вернет другое значение без изменений.

Команда jq '.a + 1'
Входные данные {"a": 7}
Вывод 8
Запуск
Команда jq '.a + .b'
Входные данные {"a": [1,2], "b": [3,4]}
Вывод [1,2,3,4]
Запуск
Команда jq '.a + null'
Входные данные {"a": 1}
Вывод 1
Запуск
Команда jq '.a + 1'
Входные данные {}
Вывод 1
Запуск
Команда jq '{a: 1} + {b: 2} + {c: 3} + {a: 42}'
Входные данные null
Вывод {"a": 42, "b": 2, "c": 3}
Запуск

Вычитание: -

Помимо обычного арифметического вычитания чисел, оператор - может использоваться для массивов, чтобы удалить все вхождения элементов второго массива из первого массива.

Команда jq '4 - .a'
Входные данные {"a":3}
Вывод 1
Запуск
Команда jq '. - ["xml", "yaml"]'
Входные данные ["xml", "yaml", "json"]
Вывод ["json"]
Запуск

Умножение, деление, остаток от деления: *, /, %

Эти инфиксные операторы ведут себя так, как и ожидается, когда им даны два числа. Деление на ноль вызывает ошибку. x % y вычисляет x по модулю y.

Умножение строки на число приводит к конкатенации этой строки столько раз. "x" * 0 производит "".

Деление одной строки на другую разделяет первую, используя вторую в качестве разделителей.

Умножение двух объектов приведет к их рекурсивному слиянию: это работает как сложение, но если оба объекта содержат значение для одного и того же ключа, и значения являются объектами, то два объекта сливаются с той же стратегией.

Команда jq '10 / . * 3'
Входные данные 5
Вывод 6
Запуск
Команда jq '. / ", "'
Входные данные "a, b,c,d, e"
Вывод ["a","b,c,d","e"]
Запуск
Команда jq '{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}'
Входные данные null
Вывод {"k": {"a": 0, "b": 2, "c": 3}}
Запуск
Команда jq '.[] | (1 / .)?'
Входные данные [1,0,-1]
Вывод 1
-1
Запуск

abs

Встроенная функция abs определена наивно как: if . < 0 then - . else . end.

Для числового входного значения это абсолютное значение. См. раздел о фильтре идентичности для последствий этого определения для числового входного значения.

Для вычисления абсолютного значения числа как числа с плавающей точкой, вы можете использовать fabs.

Команда jq 'map(abs)'
Входные данные [-10, -1.1, -1e-1]
Вывод [10,1.1,1e-1]
Запуск

length

Встроенная функция length получает длину различных типов значений:

  • Длина строки — это количество символов Юникода, которые она содержит (что будет совпадать с длиной в байтах её JSON-представления, если это чистый ASCII).

  • Длина числа — это его абсолютное значение.

  • Длина массива — это количество элементов.

  • Длина объекта — это количество пар ключ-значение.

  • Длина null равна нулю.

  • Использование length для булевого значения является ошибкой.

Команда jq '.[] | length'
Вход [[1,2], "string", {"a":2}, null, -5]
Вывод 2
6
1
0
5
Запустить

utf8bytelength

Встроенная функция utf8bytelength выводит количество байтов, используемых для кодирования строки в UTF-8.

Команда jq 'utf8bytelength'
Вход "\u03bc"
Вывод 2
Запустить

keys, keys_unsorted

Встроенная функция keys, применимая к объекту, возвращает его ключи в виде массива.

Ключи отсортированы «алфавитно» в порядке кодов Юникода. Такой порядок не имеет особого смысла для конкретного языка, но вы можете рассчитывать на его сохранение для двух объектов с одинаковым набором ключей, независимо от настроек локали.

Когда keys применяется к массиву, она возвращает допустимые индексы этого массива: целые числа от 0 до длины-1.

Функция keys_unsorted аналогична keys, но если вход — объект, то ключи не сортируются, а примерно сохраняют порядок добавления.

Команда jq 'keys'
Вход {"abc": 1, "abcd": 2, "Foo": 3}
Вывод ["Foo", "abc", "abcd"]
Запустить
Команда jq 'keys'
Вход [42,3,35]
Вывод [0,1,2]
Запустить

has(key)

Встроенная функция has возвращает, существует ли у входного объекта заданный ключ или у входного массива элемент с заданным индексом.

has($key) имеет тот же эффект, что и проверка, является ли $key членом массива, возвращаемого keys, хотя has будет быстрее.

Команда jq 'map(has("foo"))'
Вход [{"foo": 42}, {}]
Вывод [true, false]
Запустить
Команда jq 'map(has(2))'
Вход [[0,1], ["a","b","c"]]
Вывод [false, true]
Запустить

in

Встроенная функция in возвращает истину, если заданный ключ существует в объекте, или заданный индекс соответствует элементу в массиве. По сути, это обратная функция has.

Команда jq '.[] | in({"foo": 42})'
Вход ["foo", "bar"]
Вывод true
false
Запустить
Команда jq 'map(in([0,1]))'
Вход [2, 0]
Вывод [false, true]
Запустить

map(f), map_values(f)

Для любого фильтра f, map(f) и map_values(f) применяется f к каждому из значений в входном массиве или объекте, то есть к значениям .[].

В отсутствие ошибок, map(f) всегда выводит массив, тогда как map_values(f) выводит массив, если задан массив, или объект, если задан объект.

Когда вход map_values(f) — объект, выходной объект имеет те же ключи, что и входной объект, за исключением тех ключей, значения которых, когда они передаются в f, не производят никаких значений.

Ключевое различие между map(f) и map_values(f) заключается в том, что первый просто формирует массив из всех значений ($x|f) для каждого значения, $x, во входном массиве или объекте, но map_values(f) использует только first($x|f).

Конкретно, для входных объектов map_value(f) строит выходной объект, последовательно рассматривая значение first(.[$k]|f) для каждого ключа $k$ входного объекта. Если это выражение не производит никаких значений, соответствующий ключ будет опущен; в противном случае, выходной объект будет иметь это значение в качестве ключа $k$.

Вот несколько примеров, чтобы прояснить поведение map и map_values при применении к массивам. Эти примеры предполагают, что вход [1] во всех случаях:

map(.+1)          #=>  [2]
map(., .)         #=>  [1,1]
map(empty)        #=>  []

map_values(.+1)   #=>  [2]
map_values(., .)  #=>  [1]
map_values(empty) #=>  []

map(f) эквивалентно [.[] | f], а map_values(f) эквивалентно .[] |= f.

На самом деле, это их реализации.

Команда jq 'map(.+1)'
Вход [1,2,3]
Вывод [2,3,4]
Запустить
Команда jq 'map_values(.+1)'
Вход {"a": 1, "b": 2, "c": 3}
Вывод {"a": 2, "b": 3, "c": 4}
Запустить
Команда jq 'map(., .)'
Вход [1,2]
Вывод [1,1,2,2]
Запустить
Команда jq 'map_values(. // empty)'
Вход {"a": null, "b": true, "c": false}
Вывод {"b":true}
Запустить

pick(pathexps)

Выводит проекцию входного объекта или массива, определённую заданной последовательностью выражений пути, таким образом, если p — одно из этих спецификаций, то (. | p) будет иметь такое же значение, что и (. | pick(pathexps) | p). Для массивов не следует использовать отрицательные индексы и спецификации .[m:n].

Команда jq 'pick(.a, .b.c, .x)'
Вход {"a": 1, "b": {"c": 2, "d": 3}, "e": 4}
Вывод {"a":1,"b":{"c":2},"x":null}
Запустить
Команда jq 'pick(.[2], .[0], .[0])'
Вход [1,2,3,4]
Вывод [1,null,3]
Запустить

path(path_expression)

Выводит строковые представления заданного выражения пути в .. Выводы — массивы строк (ключи объектов) и/или чисел (индексы массивов).

Выражения пути — jq-выражения, такие как .a, но также и .[]. Существует два типа выражений пути: те, которые могут точно соответствовать, и те, которые не могут. Например, .a.b.c — это выражение пути точного соответствия, а .a[].b — нет.

path(exact_path_expression) будет генерировать строковое представление выражения пути, даже если оно не существует в ., если . — null или массив или объект.

path(pattern) будет генерировать строковые представления путей, соответствующих pattern, если пути существуют в ..

Обратите внимание, что выражения пути не отличаются от обычных выражений. Выражение path(..|select(type=="boolean")) выводит все пути к булевым значениям в ., и только эти пути.

Команда jq 'path(.a[0].b)'
Вход null
Вывод ["a",0,"b"]
Запустить
Команда jq '[path(..)]'
Вход {"a":[{"b":1}]}
Вывод [[],["a"],["a",0],["a",0,"b"]]
Запустить

del(path_expression)

Встроенная функция del удаляет ключ и его соответствующее значение из объекта.

Команда jq 'del(.foo)'
Вход {"foo": 42, "bar": 9001, "baz": 42}
Вывод {"bar": 9001, "baz": 42}
Запустить
Команда jq 'del(.[1, 2])'
Вход ["foo", "bar", "baz"]
Вывод ["foo"]
Запустить

getpath(PATHS)

Функция getpath выводит значения, находящиеся по каждому пути в заданном PATHS.

Команда jq 'getpath(["a","b"])'
Входные данные null
Вывод null
Запустить
Команда jq '[getpath(["a","b"], ["a","c"])]'
Входные данные {"a":{"b":0, "c":1}}
Вывод [0, 1]
Запустить

setpath(PATHS; VALUE)

Функция setpath устанавливает значение в . по указанному пути PATHS.

Команда jq 'setpath(["a","b"]; 1)'
Входные данные null
Вывод {"a": {"b": 1}}
Запустить
Команда jq 'setpath(["a","b"]; 1)'
Входные данные {"a":{"b":0}}
Вывод {"a": {"b": 1}}
Запустить
Команда jq 'setpath([0,"a"]; 1)'
Входные данные null
Вывод [{"a":1}]
Запустить

delpaths(PATHS)

Функция delpaths удаляет значения по указанным путям в .. PATHS должен быть массивом путей, где каждый путь — массив строк и чисел.

Команда jq 'delpaths([["a","b"]])'
Входные данные {"a":{"b":1},"x":{"y":2}}
Вывод {"a":{},"x":{"y":2}}
Запустить

to_entries, from_entries, with_entries(f)

Эти функции преобразуют объект в массив пар «ключ-значение» и обратно. Если to_entries получает объект, то для каждой k: v записи входных данных выходной массив содержит {"key": k, "value": v}.

from_entries выполняет обратное преобразование, а with_entries(f) — это сокращение для to_entries | map(f) | from_entries, полезное для выполнения некоторых операций со всеми ключами и значениями объекта. from_entries принимает "key", "Key", "name", "Name", "value", и "Value" в качестве ключей.

Команда jq 'to_entries'
Входные данные {"a": 1, "b": 2}
Вывод [{"key":"a", "value":1}, {"key":"b", "value":2}]
Запустить
Команда jq 'from_entries'
Входные данные [{"key":"a", "value":1}, {"key":"b", "value":2}]
Вывод {"a": 1, "b": 2}
Запустить
Команда jq 'with_entries(.key |= "KEY_" + .)'
Входные данные {"a": 1, "b": 2}
Вывод {"KEY_a": 1, "KEY_b": 2}
Запустить

select(boolean_expression)

Функция select(f) возвращает входные данные без изменений, если f возвращает true для этих данных, и не возвращает ничего в противном случае.

Она полезна для фильтрации списков: [1,2,3] | map(select(. >= 2)) даст вам [2,3].

Команда jq 'map(select(. >= 2))'
Входные данные [1,5,3,0,7]
Вывод [5,3,7]
Запустить
Команда jq '.[] | select(.id == "second")'
Входные данные [{"id": "first", "val": 1}, {"id": "second", "val": 2}]
Вывод {"id": "second", "val": 2}
Запустить

arrays, objects, iterables, booleans, numbers, normals, finites, strings, nulls, values, scalars

Эти встроенные функции выбирают только входы, которые являются массивами, объектами, итерируемыми (массивы или объекты), булевыми значениями, числами, нормальными числами, конечными числами, строками, null, не-null значениями и не-итерируемыми, соответственно.

Команда jq '.[]|numbers'
Входные данные [[],{},1,"foo",null,true,false]
Вывод 1
Запустить

empty

empty возвращает нулевые результаты. Совсем никаких. Даже null.

Иногда это полезно. Вы поймёте, если вам это понадобится :)

Команда jq '1, empty, 2'
Входные данные null
Вывод 1
2
Запустить
Команда jq '[1,2,empty,3]'
Входные данные null
Вывод [1,2,3]
Запустить

error, error(message)

Возвращает ошибку со значением входных данных или с указанным в качестве аргумента сообщением. Ошибки можно перехватить с помощью try/catch; см. ниже.

Команда jq 'try error catch .'
Входные данные "error message"
Вывод "error message"
Запустить
Команда jq 'try error("invalid value: \(.)") catch .'
Входные данные 42
Вывод "invalid value: 42"
Запустить

halt

Останавливает программу jq без дальнейших выводов. jq завершит работу со статусом выхода 0.

halt_error, halt_error(exit_code)

Останавливает программу jq без дальнейших выводов. Входные данные будут напечатаны в stderr как сырой вывод (т.е. строки не будут иметь двойных кавычек) без оформления, даже без новой строки.

Указанное exit_code (по умолчанию 5) будет статусом выхода jq.

Например, "Error: something went wrong\n"|halt_error(1).

$__loc__

Возвращает объект с ключами "file" и "line", содержащими имя файла и номер строки, где $__loc__ возникает, как значения.

Команда jq 'try error("\($__loc__)") catch .'
Входные данные null
Вывод "{\"file\":\"<top-level>\",\"line\":1}"
Запустить

paths, paths(node_filter)

paths выводит пути ко всем элементам ввода (кроме пустого списка, представляющего . самого по себе).

paths(f) выводит пути к любым значениям, для которых f равно true. То есть, paths(type == "number") выводит пути ко всем числовым значениям.

Команда jq '[paths]'
Входные данные [1,[[],{"a":2}]]
Вывод [[0],[1],[1,0],[1,1],[1,1,"a"]]
Запустить
Команда jq '[paths(type == "number")]'
Входные данные [1,[[],{"a":2}]]
Вывод [[0],[1,1,"a"]]
Запустить

add

Фильтр add принимает на вход массив и возвращает сумму элементов массива. Это может означать суммирование, конкатенацию или слияние, в зависимости от типов элементов входного массива - правила такие же, как для оператора + (описанного выше).

Если входной массив пустой, add возвращает null.

Команда jq 'add'
Входные данные ["a","b","c"]
Вывод "abc"
Запустить
Команда jq 'add'
Входные данные [1, 2, 3]
Вывод 6
Запустить
Команда jq 'add'
Входные данные []
Вывод null
Запустить

any, any(condition), any(generator; condition)

Фильтр any принимает на вход массив булевых значений и возвращает true в качестве результата, если любой из элементов массива является true.

Если входной массив пустой, any возвращает false.

Форма any(condition) применяет заданное условие к элементам входного массива.

Форма any(generator; condition) применяет заданное условие ко всем результатам данного генератора.

Команда jq 'any'
Входные данные [true, false]
Вывод true
Запустить
Команда jq 'any'
Входные данные [false, false]
Вывод false
Запустить
Команда jq 'any'
Входные данные []
Вывод false
Запустить

all, all(condition), all(generator; condition)

Фильтр all принимает на вход массив булевых значений и выдает true в качестве результата, если все элементы массива являются true.

Форма all(condition) применяет заданное условие к элементам входного массива.

Форма all(generator; condition) применяет заданное условие ко всем результатам заданного генератора.

Если входной массив пуст, all возвращает true.

Команда jq 'all'
Вход [true, false]
Результат false
Run
Команда jq 'all'
Вход [true, true]
Результат true
Run
Команда jq 'all'
Вход []
Результат true
Run

flatten, flatten(depth)

Фильтр flatten принимает на вход массив вложенных массивов и выдает плоский массив, в котором все массивы внутри исходного массива рекурсивно заменены их значениями. Вы можете передать ему аргумент, чтобы указать, сколько уровней вложенности нужно выровнять.

flatten(2) похож на flatten, но работает только до двух уровней вложенности.

Команда jq 'flatten'
Вход [1, [2], [[3]]]
Результат [1, 2, 3]
Run
Команда jq 'flatten(1)'
Вход [1, [2], [[3]]]
Результат [1, 2, [3]]
Run
Команда jq 'flatten'
Вход [[]]
Результат []
Run
Команда jq 'flatten'
Вход [{"foo": "bar"}, [{"foo": "baz"}]]
Результат [{"foo": "bar"}, {"foo": "baz"}]
Run

range(upto), range(from; upto), range(from; upto; by)

Функция range создает диапазон чисел. range(4; 10) создает 6 чисел, от 4 (включительно) до 10 (исключительно). Числа генерируются как отдельные результаты. Используйте [range(4; 10)], чтобы получить диапазон в виде массива.

Форма с одним аргументом генерирует числа от 0 до заданного числа с шагом 1.

Форма с двумя аргументами генерирует числа от from до upto с шагом 1.

Форма с тремя аргументами генерирует числа from до upto с шагом by.

Команда jq 'range(2; 4)'
Вход null
Результат 2
3
Run
Команда jq '[range(2; 4)]'
Вход null
Результат [2,3]
Run
Команда jq '[range(4)]'
Вход null
Результат [0,1,2,3]
Run
Команда jq '[range(0; 10; 3)]'
Вход null
Результат [0,3,6,9]
Run
Команда jq '[range(0; 10; -1)]'
Вход null
Результат []
Run
Команда jq '[range(0; -5; -1)]'
Вход null
Результат [0,-1,-2,-3,-4]
Run

floor

Функция floor возвращает целую часть своего числового входа.

Команда jq 'floor'
Вход 3.14159
Результат 3
Run

sqrt

Функция sqrt возвращает квадратный корень из своего числового входа.

Команда jq 'sqrt'
Вход 9
Результат 3
Run

tonumber

Функция tonumber разбирает свой входной параметр как число. Она будет правильно преобразовывать отформатированные строки в их числовые эквиваленты, оставлять числа без изменений и выдавать ошибку на всех остальных входных данных.

Команда jq '.[] | tonumber'
Входные данные [1, "1"]
Результат 1
1
Запуск

tostring

Функция tostring выводит свой входной параметр как строку. Строки остаются без изменений, а все остальные значения кодируются в формате JSON.

Команда jq '.[] | tostring'
Входные данные [1, "1", [1]]
Результат "1"
"1"
"[1]"
Запуск

type

Функция type возвращает тип своего аргумента в виде строки, который является одним из null, boolean, number, string, array или object.

Команда jq 'map(type)'
Входные данные [0, false, [], {}, null, "hello"]
Результат ["number", "boolean", "array", "object", "null", "string"]
Запуск

infinite, nan, isinfinite, isnan, isfinite, isnormal

Некоторые арифметические операции могут давать бесконечности и значения "не число" (NaN). Встроенная функция isinfinite возвращает true, если её входной параметр является бесконечностью. Встроенная функция isnan возвращает true, если её входной параметр является NaN. Встроенная функция infinite возвращает положительное бесконечное значение. Встроенная функция nan возвращает NaN. Встроенная функция isnormal возвращает true, если её входной параметр является нормальным числом.

Обратите внимание, что деление на ноль вызывает ошибку.

В настоящее время большинство арифметических операций, выполняемых над бесконечностями, NaN и субнормальными числами, не вызывают ошибок.

Команда jq '.[] | (infinite * .) < 0'
Входные данные [-1, 1]
Результат true
false
Запуск
Команда jq 'infinite, nan | type'
Входные данные null
Результат "number"
"number"
Запуск

sort, sort_by(path_expression)

Функции sort сортируют свой входной параметр, который должен быть массивом. Значения сортируются в следующем порядке:

  • null
  • false
  • true
  • числа
  • строки, в алфавитном порядке (по значению кодовой точки Unicode)
  • массивы, в лексикографическом порядке
  • объекты

Порядок сортировки объектов немного сложен: сначала они сравниваются путем сравнения их наборов ключей (как отсортированных массивов), и если их ключи равны, то значения сравниваются ключ за ключом.

sort_by может использоваться для сортировки по определенному полю объекта или путем применения любого фильтра jq. sort_by(f) сравнивает два элемента, сравнивая результат f для каждого элемента. Когда f производит несколько значений, он сначала сравнивает первые значения, а затем вторые значения, если первые значения равны, и так далее.

Команда jq 'sort'
Входные данные [8,3,null,6]
Результат [null,3,6,8]
Запуск
Команда jq 'sort_by(.foo)'
Входные данные [{"foo":4, "bar":10}, {"foo":3, "bar":10}, {"foo":2, "bar":1}]
Результат [{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":4, "bar":10}]
Запуск
Команда jq 'sort_by(.foo, .bar)'
Входные данные [{"foo":4, "bar":10}, {"foo":3, "bar":20}, {"foo":2, "bar":1}, {"foo":3, "bar":10}]
Результат [{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":3, "bar":20}, {"foo":4, "bar":10}]
Запуск

group_by(path_expression)

group_by(.foo) принимает на вход массив, группирует элементы, имеющие одинаковое поле .foo, в отдельные массивы и выдает все эти массивы как элементы большего массива, отсортированного по значению поля .foo.

Вместо .foo может использоваться любое выражение jq, а не только доступ к полю. Порядок сортировки такой же, как описано в функции sort выше.

Команда jq 'group_by(.foo)'
Входные данные [{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]
Результат [[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]
Запуск

min, max, min_by(path_exp), max_by(path_exp)

Найти минимальный или максимальный элемент входного массива.

Функции min_by(path_exp) и max_by(path_exp) позволяют указать конкретное поле или свойство для проверки, например, min_by(.foo) находит объект с наименьшим полем foo.

Команда jq 'min'
Входные данные [5,4,2,7]
Результат 2
Запустить
Команда jq 'max_by(.foo)'
Входные данные [{"foo":1, "bar":14}, {"foo":2, "bar":3}]
Результат {"foo":2, "bar":3}
Запустить

unique, unique_by(path_exp)

Функция unique принимает на вход массив и выдает массив тех же элементов, отсортированных по порядку, без дубликатов.

Функция unique_by(path_exp) будет хранить только один элемент для каждого значения, полученного путем применения аргумента. Можно представить это как создание массива, взяв один элемент из каждой группы, полученной с помощью group.

Команда jq 'unique'
Входные данные [1,2,5,3,5,3,1,3]
Результат [1,2,3,5]
Запустить
Команда jq 'unique_by(.foo)'
Входные данные [{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]
Результат [{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}]
Запустить
Команда jq 'unique_by(length)'
Входные данные ["chunky", "bacon", "kitten", "cicada", "asparagus"]
Результат ["bacon", "chunky", "asparagus"]
Запустить

reverse

Эта функция переворачивает массив.

Команда jq 'reverse'
Входные данные [1,2,3,4]
Результат [4,3,2,1]
Запустить

contains(element)

Фильтр contains(b) вернет true, если b полностью содержится во входных данных. Строка B содержится в строке A, если B является подстрокой A. Массив B содержится в массиве A, если все элементы в B содержатся в любом элементе A. Объект B содержится в объекте A, если все значения в B содержатся в значении A с тем же ключом. Предполагается, что все остальные типы содержатся друг в друге, если они равны.

Команда jq 'contains("bar")'
Входные данные "foobar"
Результат true
Запустить
Команда jq 'contains(["baz", "bar"])'
Входные данные ["foobar", "foobaz", "blarp"]
Результат true
Запустить
Команда jq 'contains(["bazzzzz", "bar"])'
Входные данные ["foobar", "foobaz", "blarp"]
Результат false
Запустить
Команда jq 'contains({foo: 12, bar: [{barp: 12}]})'
Входные данные {"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}
Результат true
Запустить
Команда jq 'contains({foo: 12, bar: [{barp: 15}]})'
Входные данные {"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}
Результат false
Запустить

indices(s)

Выводит массив, содержащий индексы в ., где встречается s. Входные данные могут быть массивом, и в этом случае, если s является массивом, то выходные индексы будут теми, где все элементы в . совпадают с элементами s.

Команда jq 'indices(", ")'
Входные данные "a,b, cd, efg, hijk"
Результат [3,7,12]
Запустить
Команда jq 'indices(1)'
Входные данные [0,1,2,1,3,1,4]
Результат [1,3,5]
Запустить
Команда jq 'indices([1,2])'
Входные данные [0,1,2,3,1,4,2,5,1,2,6,7]
Результат [1,8]
Запустить

index(s), rindex(s)

Выводит индекс первого (index) или последнего (rindex) вхождения s во входных данных.

Команда jq 'index(", ")'
Входные данные "a,b, cd, efg, hijk"
Результат 3
Запустить
Команда jq 'index(1)'
Входные данные [0,1,2,1,3,1,4]
Результат 1
Запустить
Команда jq 'index([1,2])'
Входные данные [0,1,2,3,1,4,2,5,1,2,6,7]
Результат 1
Запустить
Команда jq 'rindex(", ")'
Входные данные "a,b, cd, efg, hijk"
Результат 12
Запустить
Команда jq 'rindex(1)'
Входные данные [0,1,2,1,3,1,4]
Результат 5
Запустить
Команда jq 'rindex([1,2])'
Входные данные [0,1,2,3,1,4,2,5,1,2,6,7]
Результат 8
Запустить

inside

Фильтр inside(b) вернет true, если входные данные полностью содержатся в b. По сути, это обратная версия contains.

Команда jq 'inside("foobar")'
Входные данные "bar"
Результат true
Запустить
Команда jq 'inside(["foobar", "foobaz", "blarp"])'
Входные данные ["baz", "bar"]
Результат true
Запустить
Команда jq 'inside(["foobar", "foobaz", "blarp"])'
Входные данные ["bazzzzz", "bar"]
Результат false
Запустить
Команда jq 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})'
Входные данные {"foo": 12, "bar": [{"barp": 12}]}
Результат true
Запустить
Команда jq 'inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})'
Входные данные {"foo": 12, "bar": [{"barp": 15}]}
Результат false
Запустить

startswith(str)

Выводит true, если . начинается с указанной строковой аргумента.

Команда jq '[.[]|startswith("foo")]'
Входные данные ["fo", "foo", "barfoo", "foobar", "barfoob"]
Результат [false, true, false, true, false]
Запустить

endswith(str)

Выводит true, если . заканчивается указанной строковой аргумента.

Команда jq '[.[]|endswith("foo")]'
Входные данные ["foobar", "barfoo"]
Результат [false, true]
Запустить

combinations, combinations(n)

Выводит все комбинации элементов массивов во входном массиве. Если задан аргумент n, он выводит все комбинации n повторений входного массива.

Команда jq 'combinations'
Входные данные [[1,2], [3, 4]]
Результат [1, 3]
[1, 4]
[2, 3]
[2, 4]
Запустить
Команда jq 'combinations(2)'
Входные данные [0, 1]
Результат [0, 0]
[0, 1]
[1, 0]
[1, 1]
Запустить

ltrimstr(str)

Выводит свой входной параметр со строкой-префиксом, удалённой, если она начинается с неё.

Команда jq '[.[]|ltrimstr("foo")]'
Входные данные ["fo", "foo", "barfoo", "foobar", "afoo"]
Вывод ["fo","","barfoo","bar","afoo"]
Запустить

rtrimstr(str)

Выводит свой входной параметр со строкой-суффиксом, удалённой, если она заканчивается ею.

Команда jq '[.[]|rtrimstr("foo")]'
Входные данные ["fo", "foo", "barfoo", "foobar", "foob"]
Вывод ["fo","","bar","foobar","foob"]
Запустить

explode

Преобразует входную строку в массив числовых кодов символов строки.

Команда jq 'explode'
Входные данные "foobar"
Вывод [102,111,111,98,97,114]
Запустить

implode

Обратное преобразование к explode.

Команда jq 'implode'
Входные данные [65, 66, 67]
Вывод "ABC"
Запустить

split(str)

Разделяет входную строку по разделителю.

split также может разделять по совпадениям с регулярным выражением, если вызвана с двумя аргументами (см. раздел регулярных выражений ниже).

Команда jq 'split(", ")'
Входные данные "a, b,c,d, e, "
Вывод ["a","b,c,d","e",""]
Запустить

join(str)

Объединяет массив элементов, заданных в качестве входных данных, используя аргумент в качестве разделителя. Это обратное преобразование к split: выполнение split("foo") | join("foo") над любой входной строкой возвращает эту строку.

Числа и булевы значения во входных данных преобразуются в строки. Нулевые значения обрабатываются как пустые строки. Массивы и объекты во входных данных не поддерживаются.

Команда jq 'join(", ")'
Входные данные ["a","b,c,d","e"]
Вывод "a, b,c,d, e"
Запустить
Команда jq 'join(" ")'
Входные данные ["a",1,2.3,true,null,false]
Вывод "a 1 2.3 true false"
Запустить

ascii_downcase, ascii_upcase

Выводит копию входной строки с алфавитными символами (a-z и A-Z) в указанном регистре.

Команда jq 'ascii_upcase'
Входные данные "useful but not for é"
Вывод "USEFUL BUT NOT FOR é"
Запустить

while(cond; update)

Функция while(cond; update) позволяет многократно применять обновление к . до тех пор, пока cond не станет ложным.

Обратите внимание, что while(cond; update) внутренне определена как рекурсивная функция jq. Рекурсивные вызовы внутри while не будут потреблять дополнительной памяти, если update производит не более одного результата для каждого входа. См. расширенные темы ниже.

Команда jq '[while(.<100; .*2)]'
Входные данные 1
Вывод [1,2,4,8,16,32,64]
Запустить

repeat(exp)

Функция repeat(exp) позволяет многократно применять выражение exp к . до тех пор, пока не возникнет ошибка.

Обратите внимание, что repeat(exp) внутренне определена как рекурсивная функция jq. Рекурсивные вызовы внутри repeat не будут потреблять дополнительной памяти, если exp производит не более одного результата для каждого входа. См. расширенные темы ниже.

Команда jq '[repeat(.*2, error)?]'
Входные данные 1
Вывод [2]
Запустить

until(cond; next)

Функция until(cond; next) позволяет вам многократно применять выражение next, сначала к ., а затем к своему собственному результату, пока cond не станет истинным. Например, это может быть использовано для реализации факториальной функции (см. ниже).

Обратите внимание, что until(cond; next) внутренне определяется как рекурсивная функция jq. Рекурсивные вызовы внутри until() не будут потреблять дополнительную память, если next производит не более одного результата для каждого входного значения. См. дополнительные разделы ниже.

Команда jq '[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]'
Входные данные 4
Результат 24
Запустить

recurse(f), recurse, recurse(f; condition)

Функция recurse(f) позволяет вам искать в рекурсивной структуре и извлекать интересные данные со всех уровней. Предположим, ваш вход представляет собой файловую систему:

{"name": "/", "children": [
  {"name": "/bin", "children": [
    {"name": "/bin/ls", "children": []},
    {"name": "/bin/sh", "children": []}]},
  {"name": "/home", "children": [
    {"name": "/home/stephen", "children": [
      {"name": "/home/stephen/jq", "children": []}]}]}]}

Теперь предположим, что вы хотите извлечь все имеющиеся имена файлов. Вам нужно получить .name, .children[].name, .children[].children[].name и так далее. Вы можете сделать это с помощью:

recurse(.children[]) | .name

При вызове без аргумента recurse эквивалентно recurse(.[]?).

recurse(f) идентична recurse(f; true) и может использоваться без опасений по поводу глубины рекурсии.

recurse(f; condition) — это генератор, который начинает с вывода . и затем по очереди выводит .|f, .|f|f, .|f|f|f, ... до тех пор, пока вычисленное значение удовлетворяет условию. Например, чтобы сгенерировать все целые числа, по крайней мере в принципе, можно написать recurse(.+1; true).

Рекурсивные вызовы в recurse не будут потреблять дополнительную память, если f производит не более одного результата для каждого входного значения.

Команда jq 'recurse(.foo[])'
Входные данные {"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}
Результат {"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]}
{"foo":[]}
{"foo":[{"foo":[]}]}
{"foo":[]}
Запустить
Команда jq 'recurse'
Входные данные {"a":0,"b":[1]}
Результат {"a":0,"b":[1]}
0
[1]
1
Запустить
Команда jq 'recurse(. * .; . < 20)'
Входные данные 2
Результат 2
4
16
Запустить

walk(f)

Функция walk(f) рекурсивно применяет f к каждому компоненту входной сущности. Когда встречается массив, f сначала применяется к его элементам, а затем к самому массиву; когда встречается объект, f сначала применяется ко всем значениям, а затем к объекту. На практике f обычно будет проверять тип своего входного значения, как показано в следующих примерах. Первый пример показывает полезность обработки элементов массива массивов перед обработкой самого массива. Второй пример показывает, как все ключи всех объектов во входных данных могут быть рассмотрены для изменения.

Команда jq 'walk(if type == "array" then sort else . end)'
Входные данные [[4, 1, 7], [8, 5, 2], [3, 6, 9]]
Результат [[1,4,7],[2,5,8],[3,6,9]]
Запустить
Команда jq 'walk( if type == "object" then with_entries( .key |= sub( "^_+"; "") ) else . end )'
Входные данные [ { "_a": { "__b": 2 } } ]
Результат [{"a":{"b":2}}]
Запустить

$JQ_BUILD_CONFIGURATION

Это встроенное связывание показывает конфигурацию сборки исполняемого файла jq. Его значение не имеет определенного формата, но можно ожидать, что это будут по крайней мере аргументы командной строки ./configure, и в будущем оно может быть расширено, чтобы включать версии используемых инструментов сборки.

Обратите внимание, что это можно переопределить в командной строке с помощью --arg и связанных параметров.

$ENV, env

$ENV — это объект, представляющий переменные среды, установленные при запуске программы jq.

env выводит объект, представляющий текущую среду jq.

На данный момент нет встроенного механизма для установки переменных среды.

Команда jq '$ENV.PAGER'
Входные данные null
Результат "less"
Запустить
Команда jq 'env.PAGER'
Входные данные null
Результат "less"
Запустить

transpose

Транспонировать возможно неровную матрицу (массив массивов). Строки дополняются значениями null, поэтому результат всегда прямоугольный.

Команда jq 'transpose'
Входные данные [[1], [2,3]]
Результат [[1,2],[null,3]]
Запустить

bsearch(x)

bsearch(x) выполняет бинарный поиск x в входном массиве. Если входной массив отсортирован и содержит x, то bsearch(x) вернёт его индекс в массиве; в противном случае, если массив отсортирован, он вернёт (-1 - ix), где ix — позиция вставки, такая, что массив останется отсортированным после вставки x в ix. Если массив не отсортирован, bsearch(x) вернёт целое число, которое, вероятно, не представляет интереса.

Команда jq 'bsearch(0)'
Входные данные [0,1]
Вывод 0
Запустить
Команда jq 'bsearch(0)'
Входные данные [1,2,3]
Вывод -1
Запустить
Команда jq 'bsearch(4) as $ix | if $ix < 0 then .[-(1+$ix)] = 4 else . end'
Входные данные [1,2,3]
Вывод [1,2,3,4]
Запустить

Интерполяция строк: \(exp)

Внутри строки вы можете поместить выражение в скобки после обратной косой черты. То, что вернёт выражение, будет интерполировано в строку.

Команда jq '"Входные данные были \(.), что на единицу меньше \(.+1)"'
Входные данные 42
Вывод "Входные данные были 42, что на единицу меньше 43"
Запустить

Преобразование в/из JSON

Встроенные функции tojson и fromjson выгружают значения как тексты JSON или соответственно парсят тексты JSON в значения. Функция tojson отличается от tostring тем, что tostring возвращает строки без изменений, в то время как tojson кодирует строки как строки JSON.

...

Форматирование строк и экранирование

Синтаксис @foo используется для форматирования и экранирования строк, что полезно для построения URL-адресов, документов на языках типа HTML или XML и так далее. @foo может использоваться как отдельный фильтр, возможные экранирования:

  • @text:

Вызывает tostring, см. эту функцию для получения подробностей.

  • @json:

Сериализует входные данные как JSON.

  • @html:

Применяет экранирование HTML/XML, сопоставляя символы <>&'" с их эквивалентами сущностей &lt;, &gt;, &amp;, &apos;, &quot;.

  • @uri:

Применяет кодировку процентов, сопоставляя все зарезервированные символы URI с последовательностью %XX.

  • @csv:

Входные данные должны быть массивом, и он отображается как CSV с двойными кавычками для строк, а кавычки экранируются повтором.

  • @tsv:

Входные данные должны быть массивом, и он отображается как TSV (табулированные значения). Каждый массив входных данных будет напечатан в отдельной строке. Поля разделяются одной табуляцией (ascii 0x09). Символы переноса строки (ascii 0x0a), возврата каретки (ascii 0x0d), табуляции (ascii 0x09 ) и обратной косой черты (ascii 0x5c) будут выводиться как escape-последовательности \n, \r, \t, \\ соответственно.

  • @sh:

Входные данные экранируются подходящим образом для использования в командной строке для оболочки POSIX. Если входные данные являются массивом, вывод будет представлять собой серию строк, разделённых пробелами.

  • @base64:

Входные данные преобразуются в base64 в соответствии со спецификацией RFC 4648.

  • @base64d:

Обратная функция к @base64, входные данные декодируются в соответствии со спецификацией RFC 4648. Примечание: Если декодированная строка не является UTF-8, результаты не определены.

Этот синтаксис может быть полезно комбинирован с интерполяцией строк. Вы можете после маркера @foo следовать строковой литералом. Содержимое строковой литерала не будет экранироваться. Однако все интерполяции внутри этой строковой литерала будут экранированы. Например,

@uri "https://www.google.com/search?q=\(.search)"

выведет следующий вывод для входных данных {"search":"what is jq?"}:

"https://www.google.com/search?q=what%20is%20jq%3F"

Обратите внимание, что слеши, вопросительный знак и т.д. в URL не экранированы, так как они были частью строковой литерала.

...

Даты

jq предоставляет некоторые базовые функции обработки дат с некоторыми высокоуровневыми и низкоуровневыми встроенными функциями. Во всех случаях эти встроенные функции работают исключительно со временем в UTC.

Встроенная функция fromdateiso8601 анализирует даты и время в формате ISO 8601 и преобразует их в количество секунд с момента эпохи Unix (1970-01-01T00:00:00Z). Встроенная функция todateiso8601 выполняет обратную операцию.

Встроенная функция fromdate анализирует строки даты и времени. В настоящее время fromdate поддерживает только строки даты и времени в формате ISO 8601, но в будущем она будет пытаться анализировать строки даты и времени в большем количестве форматов.

Встроенная функция todate является псевдонимом для todateiso8601.

Встроенная функция now выводит текущее время в секундах с момента эпохи Unix.

Также предоставляются низкоуровневые jq-интерфейсы к функциям времени C-библиотеки: strptime, strftime, strflocaltime, mktime, gmtime, и localtime. Обратитесь к документации вашей операционной системы для получения информации о форматах строк, используемых в strptime и strftime. Примечание: эти интерфейсы не обязательно являются стабильными в jq, особенно в отношении их функциональности локализации.

Встроенная функция gmtime принимает количество секунд с момента эпохи Unix и выводит представление "разложенного времени" по Гринвичу в виде массива чисел, представляющих (в этом порядке): год, месяц (нулевое основание), день месяца (единичное основание), час, минуту, секунду, день недели и день года - все единичные, если не указано иное. Номер дня недели может быть неправильным на некоторых системах для дат до 1 марта 1900 года или после 31 декабря 2099 года.

Встроенная функция localtime работает как встроенная функция gmtime , но использует локальную временную зону.

Встроенная функция mktime принимает представления "разложенного времени" времени, выводимые функциями gmtime и strptime.

Встроенная функция strptime(fmt) анализирует входные строки, соответствующие аргументу fmt. Результат представлен в виде "разложенного времени", используемого функцией gmtime и выводимого функцией mktime.

Встроенная функция strftime(fmt) форматирует время (GMT) в соответствии с заданным форматом. Встроенная функция strflocaltime делает то же самое, но использует локальную временную зону.

Форматы строк для strptime и strftime описаны в типичной документации C-библиотеки. Строка формата ISO 8601 для даты и времени - "%Y-%m-%dT%H:%M:%SZ".

jq может не поддерживать некоторые или все функции работы с датой на некоторых системах. В частности, спецификаторы %u и %j для strptime(fmt) не поддерживаются на macOS.

Команда jq 'fromdate'
Входные данные "2015-03-05T23:51:47Z"
Выходные данные 1425599507
Выполнить
Команда jq 'strptime("%Y-%m-%dT%H:%M:%SZ")'
Входные данные "2015-03-05T23:51:47Z"
Выходные данные [2015,2,5,23,51,47,4,63]
Выполнить
Команда jq 'strptime("%Y-%m-%dT%H:%M:%SZ")|mktime'
Входные данные "2015-03-05T23:51:47Z"
Выходные данные 1425599507
Выполнить

Операторы в стиле SQL

jq предоставляет несколько операторов в стиле SQL.

  • INDEX(stream; index_expression):

Эта встроенная функция создаёт объект, ключи которого вычисляются с помощью данного выражения индексации, применённого к каждому значению из заданного потока.

  • JOIN($idx; stream; idx_expr; join_expr):

Эта встроенная функция объединяет значения из заданного потока со значениями заданного индекса. Ключи индекса вычисляются путём применения данного выражения индексации к каждому значению из заданного потока. Массив значения из потока и соответствующего значения из индекса подаётся в данное выражение объединения для создания каждого результата.

  • JOIN($idx; stream; idx_expr):

То же самое, что и JOIN($idx; stream; idx_expr; .).

  • JOIN($idx; idx_expr):

Эта встроенная функция объединяет входные данные . с данным индексом, применяя данное выражение индексации к . для вычисления ключа индекса. Операция объединения выполняется, как описано выше.

  • IN(s):

Эта встроенная функция выводит true , если . встречается в заданном потоке, иначе выводит false.

  • IN(source; s):

Эта встроенная функция выводит true , если какое-либо значение из потока source встречается во втором потоке, иначе выводит false.

builtins

Возвращает список всех встроенных функций в формате name/arity. Поскольку функции с одинаковым именем, но различной арностью считаются отдельными функциями, all/0, all/1, и all/2 все будут присутствовать в списке.

Условные операторы и сравнения

==, !=

Выражение 'a == b' вернёт 'true', если результаты вычисления a и b равны (то есть, если они представляют эквивалентные значения JSON), и 'false' в противном случае. В частности, строки никогда не считаются равными числам. При проверке равенства JSON-объектов порядок ключей не имеет значения. Если вы переходите из JavaScript, обратите внимание, что jq's == аналогично JavaScript's ===, оператору "строгого равенства".

!= означает "не равно", и 'a != b' возвращает значение, противоположное 'a == b'

Команда jq '. == false'
Входные данные null
Вывод false
Запустить
Команда jq '. == {"b": {"d": (4 + 1e-20), "c": 3}, "a":1}'
Входные данные {"a":1, "b": {"c": 3, "d": 4}}
Вывод true
Запустить
Команда jq '.[] == 1'
Входные данные [1, 1.0, "1", "banana"]
Вывод true
true
false
false
Запустить

if-then-else-end

if A then B else C end будет действовать так же, как B, если A возвращает значение, отличное от false или null, но будет действовать так же, как C в противном случае.

if A then B end аналогично if A then B else . end. То есть, ветка else является необязательной, и в её отсутствие результат будет эквивалентен .. Это также относится к elif с отсутствующей веткой else.

Проверка на false или null — это более упрощённое понятие "истинности", чем в JavaScript или Python, но это означает, что иногда вам придётся быть более явным относительно требуемого условия. Вы не можете проверить, например, пустая ли строка, используя if .name then A else B end; вам понадобится что-то вроде if .name == "" then A else B end.

Если условие A производит несколько результатов, то B вычисляется один раз для каждого результата, не равного false или null, и C вычисляется один раз для каждого false или null.

Можно добавить больше случаев в оператор if, используя синтаксис elif A then B.

Команда jq 'if . == 0 then "zero" elif . == 1 then "one" else "many" end'
Входные данные 2
Вывод "many"
Запустить

>, >=, <=, <

Операторы сравнения >, >=, <=, < возвращают, больше ли, больше или равно, меньше или равно или меньше левый аргумент, чем правый (соответственно).

Порядок такой же, как описано для sort выше.

Команда jq '. < 5'
Входные данные 2
Вывод true
Запустить

and, or, not

jq поддерживает обычные булевы операторы and, or, not. У них те же стандарты истинности, что и у условных выражений — false и null считаются "ложными значениями", а всё остальное — "истинными значениями".

Если операнд одного из этих операторов производит несколько результатов, сам оператор произведёт результат для каждого входного значения.

not на самом деле является встроенной функцией, а не оператором, поэтому она вызывается как фильтр, к которому можно передавать вещи, а не со специальным синтаксисом, как в .foo and .bar | not.

Эти три оператора возвращают только значения true и false, и поэтому они полезны только для настоящих булевых операций, а не для общего приема Perl/Python/Ruby "значение_которое_может_быть_null или значение_по_умолчанию". Если вы хотите использовать эту форму "или", выбирая между двумя значениями, а не вычисляя условие, см. оператор // ниже.

Команда jq '42 and "a string"'
Входные данные null
Вывод true
Запустить
Команда jq '(true, false) or false'
Входные данные null
Вывод true
false
Запустить
Команда jq '(true, true) and (true, false)'
Входные данные null
Вывод true
false
true
false
Запустить
Команда jq '[true, false | not]'
Входные данные null
Вывод [false, true]
Запустить

Оператор альтернативы: //

Оператор // производит все значения его левой части, которые не являются false или null, или, если левая часть не производит никаких значений, кроме false или null, тогда // производит все значения его правой части.

Фильтр вида a // b производит все результаты a, которые не являются false или null. Если a не производит результатов или результаты не отличаются от false или null, то a // b производит результаты b.

Это полезно для предоставления значений по умолчанию: .foo // 1 будет вычисляться как 1 , если в вводе нет элемента .foo. Это похоже на то, как or иногда используется в Python (оператор or jq предназначен для строго булевых операций).

Примечание: some_generator // defaults_here не то же самое, что и some_generator | . // defaults_here. Последнее будет производить значения по умолчанию для всех значений левой части, которые не являются false, не null, в то время как первое – нет. Правила приоритета могут вызвать путаницу. Например, в false, 1 // 2 левая часть // – это 1, а не false, 1 – false, 1 // 2 анализируется так же, как false, (1 // 2). В (false, null, 1) | . // 42 левая часть // – это ., которая всегда производит только одно значение, а в (false, null, 1) // 42 левая часть – это генератор трёх значений, и поскольку она производит значение, отличное от false и null, значение по умолчанию 42 не производится.

Команда jq 'empty // 42'
Входные данные null
Вывод 42
Запустить
Команда jq '.foo // 42'
Входные данные {"foo": 19}
Вывод 19
Запустить
Команда jq '.foo // 42'
Входные данные {}
Вывод 42
Запустить
Команда jq '(false, null, 1) // 42'
Входные данные null
Вывод 1
Запустить
Команда jq '(false, null, 1) | . // 42'
Входные данные null
Вывод 42
42
1
Запустить

try-catch

Ошибки можно перехватывать с помощью try EXP catch EXP. Первое выражение выполняется, а если оно терпит неудачу, то второе выполняется с сообщением об ошибке. Вывод обработчика, если таковой имеется, отображается так, как будто это был вывод выражения для попытки.

Форма try EXP использует empty в качестве обработчика исключений.

Команда jq 'try .a catch ". is not an object"'
Входные данные true
Вывод ". is not an object"
Запустить
Команда jq '[.[]|try .a]'
Входные данные [{}, true, {"a":1}]
Вывод [null, 1]
Запустить
Команда jq 'try error("some exception") catch .'
Входные данные true
Вывод "some exception"
Запустить

Прерывание управляющих структур

Удобное применение try/catch – это прерывание управляющих структур, таких как reduce, foreach, while, и так далее.

Например:

# Repeat an expression until it raises "break" as an
# error, then stop repeating without re-raising the error.
# But if the error caught is not "break" then re-raise it.
try repeat(exp) catch if .=="break" then empty else error

jq имеет синтаксис для именованных лексических меток для «прерывания» или «возвращения к»:

label $out | ... break $out ...

Выражение break $label_name заставит программу действовать так, как будто ближайшая (слева) label $label_name произвела empty.

Связь между break и соответствующим label является лексической: метка должна быть «видимой» из break.

Для выхода из reduce, например:

label $out | reduce .[] as $item (null; if .==false then break $out else ... end)

Следующая программа jq генерирует синтаксическую ошибку:

break $out

потому что метка $out не видна.

Подавление ошибок / Оператор необязательности: ?

Оператор ? , используемый как EXP?, является сокращением для try EXP.

Команда jq '[.[] | .a?]'
Входные данные [{}, true, {"a":1}]
Вывод [null, 1]
Запустить
Команда jq '[.[] | tonumber?]'
Входные данные ["1", "invalid", "3", 4]
Вывод [1, 3, 4]
Запустить

Регулярные выражения

jq использует библиотеку регулярных выражений Oniguruma, как и PHP, TextMate, Sublime Text и т.д., поэтому описание здесь будет сосредоточено на особенностях jq.

Oniguruma поддерживает несколько вариантов регулярных выражений, поэтому важно знать, что jq использует вариант "Perl NG" (Perl с именованными группами).

Фильтры регулярных выражений jq определены таким образом, что их можно использовать с использованием одной из этих схем:

STRING | FILTER(REGEX)
STRING | FILTER(REGEX; FLAGS)
STRING | FILTER([REGEX])
STRING | FILTER([REGEX, FLAGS])

где:

  • STRING, REGEX и FLAGS являются строками jq и подчиняются интерполяции строк jq;
  • REGEX после интерполяции строк должен быть допустимым регулярным выражением;
  • FILTER является одним из test, match или capture, как описано ниже.

Поскольку REGEX должен вычисляться в строку JSON, некоторые символы, необходимые для формирования регулярного выражения, должны быть экранированы. Например, регулярное выражение \s обозначающее пробел, будет записано как "\\s".

FLAGS — это строка, состоящая из одного или нескольких поддерживаемых флагов:

  • g - глобальный поиск (найти все совпадения, а не только первое)
  • i - поиск без учёта регистра
  • m - многострочный режим (. будет соответствовать символам новой строки)
  • n - игнорировать пустые совпадения
  • p - включены режимы s и m
  • s - однострочный режим (^ -> \A, $ -> \Z)
  • l - найти наибольшие возможные совпадения
  • x - расширенный формат регулярного выражения (игнорировать пробелы и комментарии)

Для сопоставления пробела с флагом x, используйте \s, например

jq -n '"a b" | test("a\\sb"; "x")'

Обратите внимание, что некоторые флаги также могут быть указаны в REGEX, например

jq -n '("test", "TEst", "teST", "TEST") | test("(?i)te(?-i)st")'

вычисляется как: true, true, false, false.

test(val), test(regex; flags)

Как match, но не возвращает объекты совпадений, а только true или false для того, соответствует ли регулярное выражение входным данным или нет.

Команда jq 'test("foo")'
Входные данные "foo"
Результат true
Запустить
Команда jq '.[] | test("a b c # spaces are ignored"; "ix")'
Входные данные ["xabcd", "ABC"]
Результат true
true
Запустить

match(val), match(regex; flags)

match выводит объект для каждого найденного совпадения. Совпадения имеют следующие поля:

  • offset - смещение в кодовых точках UTF-8 от начала входных данных
  • length - длина в кодовых точках UTF-8 совпадения
  • string - строка, с которой произошло совпадение
  • captures - массив объектов, представляющих захватывающие группы.

Объекты захватывающих групп имеют следующие поля:

  • offset - смещение в кодовых точках UTF-8 от начала входных данных
  • length - длина в кодовых точках UTF-8 этой захватывающей группы
  • string - захваченная строка
  • name - имя захватывающей группы (или null, если она была безымянной)

Захватывающие группы, которые не совпали ни с чем, возвращают смещение -1

Команда jq 'match("(abc)+"; "g")'
Входные данные "abc abc"
Результат {"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]}
{"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]}
Запустить
Команда jq 'match("foo")'
Входные данные "foo bar foo"
Результат {"offset": 0, "length": 3, "string": "foo", "captures": []}
Запустить
Команда jq 'match(["foo", "ig"])'
Входные данные "foo bar FOO"
Результат {"offset": 0, "length": 3, "string": "foo", "captures": []}
{"offset": 8, "length": 3, "string": "FOO", "captures": []}
Запустить
Команда jq 'match("foo (?<bar123>bar)? foo"; "ig")'
Входные данные "foo bar foo foo foo"
Результат {"offset": 0, "length": 11, "string": "foo bar foo", "captures": [{"offset": 4, "length": 3, "string": "bar", "name": "bar123"}]}
{"offset": 12, "length": 8, "string": "foo foo", "captures": [{"offset": -1, "length": 0, "string": null, "name": "bar123"}]}
Запустить
Команда jq '[ match("."; "g")] | length'
Входные данные "abc"
Результат 3
Запустить

capture(val), capture(regex; flags)

Собирает именованные захваты в объект JSON, где имя каждого захвата является ключом, а соответствующая строка — значением.

Команда jq 'capture("(?<a>[a-z]+)-(?<n>[0-9]+)")'
Входные данные "xyzzy-14"
Результат { "a": "xyzzy", "n": "14" }
Запустить

scan(regex), scan(regex; flags)

Выдает поток непересекающихся подстрок входных данных, которые соответствуют регулярному выражению в соответствии с флагами, если таковые были указаны. Если совпадений нет, поток пуст. Чтобы захватить все совпадения для каждой входной строки, используйте идиому [ expr ], например [ scan(regex) ].

Команда jq 'scan("c")'
Входные данные "abcdefabc"
Результат "c"
"c"
Запустить

split(regex; flags)

Разделяет входную строку на каждой совпадении с регулярным выражением.

Для обратной совместимости, когда вызывается с одним аргументом, split разделяет по строке, а не по регулярному выражению.

Команда jq 'split(", *"; null)'
Вход "ab,cd, ef"
Вывод ["ab","cd","ef"]
Запустить

splits(regex), splits(regex; flags)

Они дают те же результаты, что и их split аналоги, но в виде потока, а не массива.

Команда jq 'splits(", *")'
Вход "ab,cd, ef, gh"
Вывод "ab"
"cd"
"ef"
"gh"
Запустить

sub(regex; tostring), sub(regex; tostring; flags)

Вывести строку, полученную путём замены первого совпадения регулярного выражения во входной строке на tostring, после интерполяции. tostring должна быть jq-строкой или потоком таких строк, каждая из которых может содержать ссылки на именованные захватчики. Именные захватчики фактически представляются как объект JSON (как построенный capture) для tostring, поэтому ссылка на захваченную переменную с именем "x" будет иметь вид: "\(.x)".

Команда jq 'sub("[^a-z]*(?<x>[a-z]+)"; "Z\(.x)"; "g")'
Вход "123abc456def"
Вывод "ZabcZdef"
Запустить
Команда jq '[sub("(?<a>.)"; "\(.a|ascii_upcase)", "\(.a|ascii_downcase)")]'
Вход "aB"
Вывод ["AB","aB"]
Запустить

gsub(regex; tostring), gsub(regex; tostring; flags)

gsub аналогично sub, но все непересекающиеся вхождения регулярного выражения заменяются tostring, после интерполяции. Если второй аргумент является потоком jq-строк, то gsub будет производить соответствующий поток JSON-строк.

Команда jq 'gsub("(?<x>.)[^a]*"; "+\(.x)-")'
Вход "Abcabc"
Вывод "+A-+a-"
Запустить
Команда jq '[gsub("p"; "a", "b")]'
Вход "p"
Вывод ["a","b"]
Запустить

Дополнительные возможности

Переменные являются абсолютной необходимостью в большинстве языков программирования, но в jq они отнесены к «дополнительным возможностям».

В большинстве языков переменные — единственный способ передачи данных. Если вы вычисляете значение и хотите использовать его более одного раза, вам нужно сохранить его в переменной. Чтобы передать значение в другую часть программы, этой части программы потребуется определить переменную (в качестве параметра функции, члена объекта или чего-либо подобного), в которую можно поместить данные.

Также можно определять функции в jq, хотя эта функция наиболее полезна для определения стандартной библиотеки jq (многие функции jq, такие как map и select, фактически написаны на jq).

jq имеет операторы сокращения, которые очень мощные, но немного сложные. Опять же, они в основном используются внутри, для определения полезных частей стандартной библиотеки jq.

Возможно, вначале это не очевидно, но jq ориентирован на генераторы (да, как и во многих других языках). Предоставляются некоторые утилиты для работы с генераторами.

Доступна некоторая минимальная поддержка ввода-вывода (кроме чтения JSON из стандартного ввода и записи JSON в стандартный вывод).

Наконец, есть система модулей/библиотек.

Оператор привязки переменных/символов: ... as $identifier | ...

В jq все фильтры имеют вход и выход, поэтому для передачи значения из одной части программы в другую не требуется ручная передача. Многие выражения, например, a + b, передают свой вход двум различным подвыражениям (здесь a и b оба получают тот же вход), поэтому переменные обычно не нужны для использования значения дважды.

Например, вычисление среднего значения массива чисел требует нескольких переменных в большинстве языков — по крайней мере, одной для хранения массива, возможно, одной для каждого элемента или для счётчика цикла. В jq это просто add / length — выражение add получает массив и вычисляет его сумму, а выражение length получает массив и вычисляет его длину.

Таким образом, в jq обычно существует более чистый способ решения большинства задач, чем определение переменных. Тем не менее, иногда они упрощают задачу, поэтому jq позволяет определять переменные с помощью expression as $variable. Все имена переменных начинаются с $. Вот немного менее удобная версия примера вычисления среднего значения массива:

length as $array_length | add / $array_length

Нам понадобится более сложная задача, чтобы найти ситуацию, в которой использование переменных действительно облегчит нам жизнь.

Предположим, у нас есть массив записей блога со полями «автор» и «заголовок», а также другой объект, который используется для сопоставления имен пользователей авторов с реальными именами. Наш вход выглядит следующим образом:

{"posts": [{"title": "First post", "author": "anon"},
           {"title": "A well-written article", "author": "person1"}],
 "realnames": {"anon": "Anonymous Coward",
               "person1": "Person McPherson"}}

Мы хотим получить записи с полем «автор», содержащим реальное имя, как в:

{"title": "First post", "author": "Anonymous Coward"}
{"title": "A well-written article", "author": "Person McPherson"}

Мы используем переменную $names для хранения объекта realnames, чтобы мы могли ссылаться на него позже при поиске имён пользователей авторов:

.realnames as $names | .posts[] | {title, author: $names[.author]}

Выражение exp as $x | ... означает: для каждого значения выражения exp, выполните остальную часть конвейера с исходным полным входом и со значением $x, установленным на это значение. Таким образом, as выполняет функцию цикла foreach.

Так же, как {foo} — удобный способ записи {foo: .foo}, так и {$foo} — удобный способ записи {foo: $foo}.

Несколько переменных можно объявить, используя одно выражение as выражением, указав шаблон, который соответствует структуре ввода (это называется «распаковкой»):

. as {realnames: $names, posts: [$first, $second]} | ...

Объявления переменных в шаблонах массивов (например, . as [$first, $second]) привязываются к элементам массива с элемента от индекса ноль и далее в порядке. Когда значения в массиве отсутствует для элемента шаблона массива, null привязывается к этой переменной.

Переменные имеют область действия в остальной части выражения, которое их определяет, поэтому

.realnames as $names | (.posts[] | {title, author: $names[.author]})

будет работать, но

(.realnames as $names | .posts[]) | {title, author: $names[.author]}

не будет.

Для теоретиков языков программирования точнее сказать, что переменные jq — это лексически связанные привязки. В частности, невозможно изменить значение привязки; можно только установить новую привязку с тем же именем, но которая не будет видна там, где была старая.

Команда jq '.bar as $x | .foo | . + $x'
Вход {"foo":10, "bar":200}
Вывод 210
Выполнить
Команда jq '. as $i|[(.*2|. as $i| $i), $i]'
Вход 5
Вывод [10,5]
Выполнить
Команда jq '. as [$a, $b, {c: $c}] | $a + $b + $c'
Вход [2, 3, {"c": 4, "d": 5}]
Вывод 9
Выполнить
Команда jq '.[] as [$a, $b] | {a: $a, b: $b}'
Вход [[0], [0, 1], [2, 1, 0]]
Вывод {"a":0,"b":null}
{"a":0,"b":1}
{"a":2,"b":1}
Выполнить

Альтернативный оператор деструктуризации: ?//

Альтернативный оператор деструктуризации предоставляет краткий механизм для деструктуризации входных данных, которые могут принимать одну из нескольких форм.

Предположим, у нас есть API, который возвращает список ресурсов и связанных с ними событий, и мы хотим получить user_id и timestamp первого события для каждого ресурса. API (неумело преобразованный из XML) будет заключать события в массив только в том случае, если у ресурса несколько событий:

{"resources": [{"id": 1, "kind": "widget", "events": {"action": "create", "user_id": 1, "ts": 13}},
               {"id": 2, "kind": "widget", "events": [{"action": "create", "user_id": 1, "ts": 14}, {"action": "destroy", "user_id": 1, "ts": 15}]}]}

Мы можем использовать альтернативный оператор деструктуризации для простого решения этой проблемы структурных изменений:

.resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$user_id, $ts}]} | {$user_id, $kind, $id, $ts}

Или, если мы не уверены, является ли входной массив значений или объект:

.[] as [$id, $kind, $user_id, $ts] ?// {$id, $kind, $user_id, $ts} | ...

Каждая альтернатива не обязана определять все те же переменные, но все именованные переменные будут доступны последующему выражению. Переменные, не найденные в выбранной альтернативе, будут null:

.resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$first_user_id, $first_ts}]} | {$user_id, $first_user_id, $kind, $id, $ts, $first_ts}

Кроме того, если последующее выражение возвращает ошибку, альтернативный оператор попытается использовать следующее привязку. Ошибки, возникающие в финальной альтернативе, передаются дальше.

[[3]] | .[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end
Команда jq '.[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, $d, $e}'
Входные данные [{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}]
Результат {"a":1,"b":2,"d":3,"e":4}
{"a":1,"b":2,"d":3,"e":4}
Запустить
Команда jq '.[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e}'
Входные данные [{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}]
Результат {"a":1,"b":2,"d":3,"e":null}
{"a":1,"b":2,"d":null,"e":4}
Запустить
Команда jq '.[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end'
Входные данные [[3]]
Результат {"a":null,"b":3}
Запустить

Определение функций

Вы можете дать фильтру имя, используя синтаксис "def":

def increment: . + 1;

С этого момента, increment можно использовать как фильтр, как и встроенную функцию (на самом деле, так определены многие встроенные функции). Функция может принимать аргументы:

def map(f): [.[] | f];

Аргументы передаются как фильтры (функции без аргументов), а не как значения. Один и тот же аргумент может ссылаться несколько раз с разными входными данными (здесь f выполняется для каждого элемента входного массива). Аргументы функции работают больше как обратные вызовы, чем как аргументы значений. Это важно понимать. Рассмотрим:

def foo(f): f|f;
5|foo(.*2)

Результат будет 20, потому что f является .*2, и во время первого вызова f . будет 5, а во второй раз он будет 10 (5 * 2), поэтому результат будет 20. Аргументы функции являются фильтрами, а фильтры ожидают входные данные при вызове.

Если вам нужно поведение аргумента-значения для определения простых функций, вы можете просто использовать переменную:

def addvalue(f): f as $f | map(. + $f);

Или использовать сокращенный вариант:

def addvalue($f): ...;

С любым из этих определений, addvalue(.foo) будет добавлять поле .foo текущего ввода к каждому элементу массива. Обратите внимание, что вызов addvalue(.[]) приведет к тому, что часть map(. + $f) будет вычисляться один раз для каждого значения в значении . в точке вызова.

Разрешено несколько определений с использованием одного и того же имени функции. Каждое переопределение заменяет предыдущее для того же количества аргументов функции, но только для ссылок из функций (или основной программы), последующих за переопределением. См. также раздел ниже о области видимости.

Команда jq 'def addvalue(f): . + [f]; map(addvalue(.[0]))'
Входные данные [[1,2],[10,20]]
Результат [[1,2,1], [10,20,10]]
Запустить
Команда jq 'def addvalue(f): f as $x | map(. + $x); addvalue(.[0])'
Входные данные [[1,2],[10,20]]
Результат [[1,2,1,2], [10,20,1,2]]
Запустить

Область видимости

В jq есть два типа символов: привязки значений (также называемые «переменными») и функции. Оба имеют лексическую область видимости, при этом выражения могут ссылаться только на символы, которые были определены «слева» от них. Единственным исключением из этого правила является то, что функции могут ссылаться сами на себя, чтобы создавать рекурсивные функции.

Например, в следующем выражении есть привязка, которая видна «справа» от нее, ... | .*3 as $times_three | [. + $times_three] | ..., но не «слева». Рассмотрим теперь это выражение, ... | (.*3 as $times_three | [. + $times_three]) | ...: здесь привязка $times_three не видна за закрывающей скобкой.

isempty(exp)

Возвращает true, если exp не производит выходных данных, false в противном случае.

Команда jq 'isempty(empty)'
Входные данные null
Результат true
Запустить
Команда jq 'isempty(.[])'
Входные данные []
Результат true
Запустить
Команда jq 'isempty(.[])'
Входные данные [1,2,3]
Результат false
Запустить

limit(n; exp)

Функция limit извлекает до n выходных данных из exp.

Команда jq '[limit(3;.[])]'
Входные данные [0,1,2,3,4,5,6,7,8,9]
Результат [0,1,2]
Запустить

first(expr), last(expr), nth(n; expr)

Функции first(expr) и last(expr) извлекают первое и последнее значения из expr, соответственно.

Функция nth(n; expr) извлекает n-ое значение, выводимое expr. Обратите внимание, что nth(n; expr) не поддерживает отрицательные значения n.

Команда jq '[first(range(.)), last(range(.)), nth(./2; range(.))]'
Входные данные 10
Выходные данные [0,9,5]
Запустить

first, last, nth(n)

Функции first и last извлекают первое и последнее значения из любого массива в ..

Функция nth(n) извлекает n-ое значение любого массива в ..

Команда jq '[range(.)]|[first, last, nth(5)]'
Входные данные 10
Выходные данные [0,9,5]
Запустить

reduce

Синтаксис reduce позволяет объединять все результаты выражения, накапливая их в одном ответе. Форма: reduce EXP as $var (INIT; UPDATE). В качестве примера мы передадим [1,2,3] этому выражению:

reduce .[] as $item (0; . + $item)

Для каждого результата, который .[] производит, . + $item запускается для накопления текущей суммы, начиная с 0 в качестве входного значения. В этом примере .[] производит результаты 1, 2 и 3, поэтому эффект аналогичен запуску чего-то подобного:

0 | 1 as $item | . + $item |
    2 as $item | . + $item |
    3 as $item | . + $item
Команда jq 'reduce .[] as $item (0; . + $item)'
Входные данные [1,2,3,4,5]
Выходные данные 15
Запустить
Команда jq 'reduce .[] as [$i,$j] (0; . + $i * $j)'
Входные данные [[1,2],[3,4],[5,6]]
Выходные данные 44
Запустить
Команда jq 'reduce .[] as {$x,$y} (null; .x += $x | .y += [$y])'
Входные данные [{"x":"a","y":1},{"x":"b","y":2},{"x":"c","y":3}]
Выходные данные {"x":"abc","y":[1,2,3]}
Запустить

foreach

Синтаксис foreach похож на reduce, но предназначен для создания limit и редукторов, которые производят промежуточные результаты.

Форма: foreach EXP as $var (INIT; UPDATE; EXTRACT). В качестве примера мы передадим [1,2,3] этому выражению:

foreach .[] as $item (0; . + $item; [$item, . * 2])

Как и синтаксис reduce, . + $item запускается для каждого результата, который .[] производит, но [$item, . * 2] запускается для каждого промежуточного значения. В этом примере, поскольку промежуточные значения равны 1, 3 и 6, выражение foreach производит [1,2], [2,6] и [3,12]. Таким образом, эффект аналогичен запуску чего-то подобного:

0 | 1 as $item | . + $item | [$item, . * 2],
    2 as $item | . + $item | [$item, . * 2],
    3 as $item | . + $item | [$item, . * 2]

Когда EXTRACT опущен, используется тождественный фильтр. То есть он выводит промежуточные значения такими, какие они есть.

Команда jq 'foreach .[] as $item (0; . + $item)'
Входные данные [1,2,3,4,5]
Выходные данные 1
3
6
10
15
Запустить
Команда jq 'foreach .[] as $item (0; . + $item; [$item, . * 2])'
Входные данные [1,2,3,4,5]
Выходные данные [1,2]
[2,6]
[3,12]
[4,20]
[5,30]
Запустить
Команда jq 'foreach .[] as $item (0; . + 1; {index: ., $item})'
Входные данные ["foo", "bar", "baz"]
Выходные данные {"index":1,"item":"foo"}
{"index":2,"item":"bar"}
{"index":3,"item":"baz"}
Запустить

Рекурсия

Как описано выше, recurse использует рекурсию, и любая функция jq может быть рекурсивной. Встроенная функция while также реализована с использованием рекурсии.

Рекурсивные вызовы оптимизируются, когда выражение слева от рекурсивного вызова выводит своё последнее значение. На практике это означает, что выражение слева от рекурсивного вызова не должно производить более одного результата для каждого входного значения.

Например:

def recurse(f): def r: ., (f | select(. != null) | r); r;

def while(cond; update):
  def _while:
    if cond then ., (update | _while) else empty end;
  _while;

def repeat(exp):
  def _repeat:
    exp, _repeat;
  _repeat;

Генераторы и итераторы

Некоторые операторы и функции jq фактически являются генераторами, так как они могут производить ноль, одно или более значений для каждого входного значения, как можно ожидать в других языках программирования, имеющих генераторы. Например, .[] генерирует все значения в своём входе (который должен быть массивом или объектом), range(0; 10) генерирует целые числа от 0 до 10 и так далее.

Даже оператор запятой является генератором, генерирующим сначала значения, сгенерированные выражением слева от запятой, а затем значения, сгенерированные выражением справа от запятой.

Встроенная функция empty — это генератор, который производит ноль выходов. Встроенная функция empty возвращается к предыдущему выражению генератора.

Все функции jq могут быть генераторами, просто используя встроенные генераторы. Также возможно создать новые генераторы, используя только рекурсию и оператор запятой. Если рекурсивные вызовы находятся «в хвостовой позиции», то генератор будет эффективным. В примере ниже рекурсивный вызов _range к самому себе находится в хвостовой позиции. Пример демонстрирует три продвинутых темы: хвостовую рекурсию, создание генераторов и подфункции.

Команда jq 'def range(init; upto; by): def _range: if (by > 0 and . < upto) or (by < 0 and . > upto) then ., ((.+by)|_range) else . end; if by == 0 then init else init|_range end | select((by > 0 and . < upto) or (by < 0 and . > upto)); range(0; 10; 3)'
Вход null
Вывод 0
3
6
9
Запустить
Команда jq 'def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; [while(.<100; .*2)]'
Вход 1
Вывод [1,2,4,8,16,32,64]
Запустить

Математика

В настоящее время jq поддерживает только числа с плавающей запятой двойной точности IEEE754 (64 бита).

Помимо простых арифметических операторов, таких как +, jq также имеет большинство стандартных математических функций из библиотеки C math. Функции C math, принимающие один аргумент (например, sin()), доступны как функции jq без аргументов. Функции C math, принимающие два аргумента (например, pow()), доступны как функции jq с двумя аргументами, которые игнорируют .. Функции C math, принимающие три аргумента, доступны как функции jq с тремя аргументами, которые игнорируют ..

Доступность стандартных математических функций зависит от наличия соответствующих математических функций в вашей операционной системе и библиотеке C math. Недоступные математические функции будут определены, но вызовут ошибку.

Функции C math с одним входом: acos acosh asin asinh atan atanh cbrt ceil cos cosh erf erfc exp exp10 exp2 expm1 fabs floor gamma j0 j1 lgamma log log10 log1p log2 logb nearbyint pow10 rint round significand sin sinh sqrt tan tanh tgamma trunc y0 y1.

Функции C math с двумя входами: atan2 copysign drem fdim fmax fmin fmod frexp hypot jn ldexp modf nextafter nexttoward pow remainder scalb scalbln yn.

Функции C math с тремя входами: fma.

Для получения дополнительной информации о каждой из них обратитесь к руководству вашей системы.

Ввод/вывод

В настоящее время jq имеет минимальную поддержку ввода/вывода, в основном в виде управления временем чтения входных данных. Для этого предоставляются две встроенные функции: input и inputs, которые считывают данные из тех же источников (например, stdin, файлы, указанные в командной строке), что и jq само по себе. Эти две встроенные функции и собственные действия чтения jq могут чередоваться. Они обычно используются в сочетании с опцией нулевого ввода -n для предотвращения неявного чтения одного ввода.

Две встроенные функции обеспечивают минимальные возможности вывода: debug, и stderr. (Напомним, что выходные значения программы jq всегда выводятся как тексты JSON в stdout.) Встроенная функция debug может иметь поведение, специфичное для приложения, например, для исполняемых файлов, использующих API libjq C, но не являющихся самим исполняемым файлом jq. Встроенная функция stderr выводит свой вход в сыром виде в stder без дополнительного форматирования, даже без новой строки.

Большинство встроенных функций jq являются референтно-прозрачными и генерируют постоянные и воспроизводимые потоки значений при применении к постоянным входам. Это не относится к функциям ввода/вывода.

input

Выводит один новый вход.

Обратите внимание, что при использовании input обычно необходимо вызвать jq с опцией командной строки -n, в противном случае первое значение будет потеряно.

echo 1 2 3 4 | jq '[., input]' # [1,2] [3,4]

inputs

Выводит все оставшиеся входы по одному.

Это в первую очередь полезно для редукций над входами программы. Обратите внимание, что при использовании inputs обычно необходимо вызвать jq с опцией командной строки -n, в противном случае первое значение будет потеряно.

echo 1 2 3 | jq -n 'reduce inputs as $i (0; . + $i)' # 6

debug, debug(msgs)

Эти два фильтра подобны ., но имеют побочное действие — вывод одного или нескольких сообщений в stderr.

Сообщение, выводимое фильтром debug, имеет вид

["DEBUG:",<input-value>]

где <input-value> — компактное представление входного значения. Этот формат может быть изменён в будущем.

Фильтр debug(msgs) определён как (msgs | debug | empty), ., что обеспечивает большую гибкость в содержании сообщения, а также позволяет создавать многострочные отладочные утверждения.

Например, выражение:

1 as $x | 2 | debug("Entering function foo with $x == \($x)", .) | (.+1)

выведет значение 3, но с двумя следующими строками в stderr:

["DEBUG:","Entering function foo with $x == 1"]
["DEBUG:",2]

stderr

Выводит свой вход в сыром и компактном формате в stderr без дополнительного форматирования, даже без новой строки.

input_filename

Возвращает имя файла, вход которого в данный момент фильтруется. Обратите внимание, что это не будет работать должным образом, если jq не запущен в локале UTF-8.

input_line_number

Возвращает номер строки текущего входного значения.

Потоковая обработка

С опцией --stream jq может парсить входные тексты потоковым способом, позволяя программам jq начать обработку больших JSON-текстов немедленно, а не после завершения парсинга. Если у вас есть один JSON-текст размером 1 ГБ, потоковая обработка позволит вам обработать его намного быстрее.

Однако потоковая обработка не так проста, так как программа jq будет получать [<path>, <leaf-value>] (и несколько других форм) в качестве входных данных.

Предоставлено несколько встроенных функций, чтобы облегчить обработку потоков.

Примеры ниже используют потоковую форму [0,[1]], которая является [[0],0],[[1,0],1],[[1,0]],[[1]].

Потоковые формы включают [<path>, <leaf-value>] (чтобы указать любое скалярное значение, пустой массив или пустой объект) и [<path>] (чтобы указать конец массива или объекта). Будущие версии jq с --stream и --seq могут выводить дополнительные формы, такие как ["error message"], когда входной текст не удаётся разобрать.

truncate_stream(stream_expression)

Принимает число в качестве входных данных и обрезает соответствующее количество элементов пути слева из выходных данных заданного потокового выражения.

Команда jq 'truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]])'
Входные данные 1
Выходные данные [[0],2]
[[0]]
Запуск

fromstream(stream_expression)

Выводит значения, соответствующие выходным данным потокового выражения.

Команда jq 'fromstream(1|truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]]))'
Входные данные null
Выходные данные [2]
Запуск

tostream

Встроенная функция tostream выводит потоковую форму своего входного значения.

Команда jq '. as $dot|fromstream($dot|tostream)|.==$dot'
Входные данные [0,[1,{"a":1},{"b":2}]]
Выходные данные true
Запуск

Присвоение

Присвоение работает немного иначе в jq, чем в большинстве языков программирования. jq не различает ссылки и копии чего-либо — два объекта или массива либо равны, либо не равны, без дополнительного понятия "один и тот же объект" или "не тот же объект".

Если у объекта есть два поля, которые являются массивами, .foo и .bar, и вы добавляете что-то к .foo, то .bar не увеличится, даже если вы ранее задали .bar = .foo. Если вы привыкли программировать на языках, таких как Python, Java, Ruby, JavaScript и т. д., то можно представить, что jq делает полную глубокую копию каждого объекта перед присвоением (для повышения производительности он на самом деле этого не делает, но это общая идея).

Это означает, что невозможно создать циклические значения в jq (например, массив, первый элемент которого — сам этот массив). Это вполне преднамеренно и гарантирует, что всё, что может создать программа jq, может быть представлено в формате JSON.

Все операторы присвоения в jq имеют выражения путей слева (LHS). Правая часть (RHS) предоставляет значения для установки по путям, указанным выражениями путей LHS.

Значения в jq всегда неизменяемы. Внутренне присвоение работает путём использования редукции для вычисления новых, заменяющих значений для . , которым были применены все желаемые присваивания к ., а затем вывода изменённого значения. Это может быть продемонстрировано на этом примере: {a:{b:{c:1}}} | (.a.b|=3), .. Это выведет {"a":{"b":3}} и {"a":{"b":{"c":1}}} , потому что последнее подвыражение . видит исходное значение, а не изменённое.

Большинству пользователей потребуется использовать операторы присвоения с модификацией, такие как |= или +=, а не =.

Обратите внимание, что LHS операторов присвоения ссылается на значение в .. Таким образом $var.foo = 1 не будет работать как ожидается ($var.foo не является допустимым или полезным выражением пути в .); используйте $var | .foo = 1 вместо этого.

Также обратите внимание, что .a,.b=0 не устанавливает .a и .b, но (.a,.b)=0 устанавливает оба.

Операция обновления: |=

Это оператор "обновления" |=. Он принимает фильтр в правой части и вычисляет новое значение для свойства ., которому присваивается значение, пропуская старое значение через это выражение. Например, (.foo, .bar) |= .+1 создаст объект со свойством foo , установленным в значение foo входных данных плюс 1, и свойством bar , установленным в значение bar входных данных плюс 1.

Левая часть может быть любым общим выражением пути; см. path().

Обратите внимание, что левая часть |= ссылается на значение в .. Таким образом $var.foo |= . + 1 не будет работать как ожидается ($var.foo не является допустимым или полезным выражением пути в .); используйте $var | .foo |= . + 1 вместо этого.

Если правая часть не выводит никаких значений (т.е., empty), то путь в левой части будет удалён, как в del(path).

Если правая часть выводит несколько значений, будет использовано только первое (ПРИМЕЧАНИЕ ПО СОГЛАСОВАНИЮ: в jq 1.5 и более ранних версиях использовалось только последнее).

Команда jq '(..|select(type=="boolean")) |= if . then 1 else 0 end'
Входные данные [true,false,[5,true,[true,[false]],false]]
Вывод [1,0,[5,1,[1,[0]],0]]
Запустить

Арифметическое присвоение с обновлением: +=, -=, *=, /=, %=, //=

В jq есть несколько операторов вида a op= b, которые все эквивалентны a |= . op b. Таким образом, += 1 можно использовать для увеличения значений, что эквивалентно |= . + 1.

Команда jq '.foo += 1'
Входные данные {"foo": 42}
Вывод {"foo": 43}
Запустить

Простое присвоение: =

Это оператор простого присвоения. В отличие от других, входные данные для правой части (RHS) такие же, как и входные данные для левой части (LHS), а не значение по пути LHS, и все значения, выведенные RHS, будут использованы (как показано ниже).

Если RHS = генерирует несколько значений, то для каждого такого значения jq установит пути в левой части в значение, а затем выведет изменённые .. Например, (.a,.b) = range(2) выводит {"a":0,"b":0}, а затем {"a":1,"b":1}. Операции присвоения с обновлением (см. выше) этого не делают.

Этот пример должен продемонстрировать разницу между = и |=:

Предоставьте входные данные {"a": {"b": 10}, "b": 20} программам

.a = .b

и

.a |= .b

В первом случае значение поля a входных данных будет установлено в значение поля b входных данных, и будет выведен результат {"a": 20, "b": 20}. Во втором случае значение поля a входных данных будет установлено в значение поля a входных данных, а именно в поле b , и будет выведен результат {"a": 10, "b": 20}.

Сложные присваивания

В jq допускается гораздо больше элементов в левой части оператора присваивания, чем в большинстве языков. Мы уже видели простые обращения к полям в левой части, и нет ничего удивительного в том, что обращение к элементам массива работает также:

.posts[0].title = "JQ Manual"

Что может удивить, так это то, что выражение слева может дать несколько результатов, относящихся к различным точкам входного документа:

.posts[].comments |= . + ["this is great"]

В данном примере к массиву "comments" каждого поста во входных данных (где входные данные — это объект со свойством "posts", которое представляет собой массив постов) добавляется строка "this is great".

Когда jq сталкивается с присваиванием типа 'a = b', оно записывает "путь", пройденный для выбора части входного документа при выполнении a. Этот путь затем используется для нахождения части входных данных, которую нужно изменить при выполнении присваивания. Любой фильтр может быть использован в левой части знака равенства — все пути, которые он выбирает из входных данных, будут использованы для выполнения присваивания.

Это очень мощная операция. Предположим, мы хотим добавить комментарий к записям блога, используя те же входные данные "blog", что и выше. На этот раз мы хотим добавить комментарий только к записям, написанным "stedolan". Мы можем найти эти записи с помощью функции "select", описанной ранее:

.posts[] | select(.author == "stedolan")

Пути, предоставленные этой операцией, указывают на каждую запись, написанную "stedolan", и мы можем добавить комментарии к каждой из них таким же образом, как и раньше:

(.posts[] | select(.author == "stedolan") | .comments) |=
    . + ["terrible."]

Модули

jq имеет систему библиотек/модулей. Модули — это файлы, имена которых оканчиваются на .jq.

Модули, импортированные программой, ищутся в стандартном пути поиска (см. ниже). Директивы import и include позволяют импортеру изменить этот путь.

Пути в пути поиска подвержены различным подстановкам.

Для путей, начинающихся с ~/, домашний каталог пользователя подставляется вместо ~.

Для путей, начинающихся с $ORIGIN/, директория, в которой расположен исполняемый файл jq, подставляется вместо $ORIGIN.

Для путей, начинающихся с ./ или путей, являющихся ., путь включающего файла подставляется вместо .. Для программ верхнего уровня, заданных в командной строке, используется текущий каталог.

Директивы импорта могут необязательно указывать путь поиска, к которому добавляется стандартный.

Стандартный путь поиска — это путь поиска, заданный параметром командной строки -L , иначе ["~/.jq", "$ORIGIN/../lib/jq", "$ORIGIN/../lib"].

Пустые и нулевые элементы пути прекращают обработку пути поиска.

Зависимость с относительным путем foo/bar будет искаться в foo/bar.jq и foo/bar/bar.jq в заданном пути поиска. Это предназначено для возможности размещения модулей в каталоге вместе с, например, файлами системы контроля версий, файлами README и т. д., а также для возможности использования модулей из одного файла.

Последовательные компоненты с одинаковым именем не допускаются для предотвращения неоднозначности (например, foo/foo).

Например, с помощью -L$HOME/.jq модуль foo можно найти в $HOME/.jq/foo.jq и $HOME/.jq/foo/foo.jq.

Если $HOME/.jq является файлом, он подключается к основной программе.

import RelativePathString as NAME [<metadata>];

Импортирует модуль, найденный по заданному пути относительно каталога в пути поиска. К строке относительного пути будет добавлен суффикс .jq. Символы модуля будут иметь префикс NAME::.

Необязательные метаданные должны быть выражением jq константы. Это должно быть объект с ключами, такими как homepage и т. д. В настоящее время jq использует только ключ/значение search метаданных. Метаданные также доступны пользователям через встроенную функцию modulemeta.

Ключ search в метаданных, если он присутствует, должен иметь строковое или массивно-строковое значение (массив строк); это путь поиска, который будет добавлен к верхнему уровню пути поиска.

include RelativePathString [<metadata>];

Импортирует модуль, найденный по заданному пути относительно каталога в пути поиска, как если бы он был включен на месте. К строке относительного пути будет добавлен суффикс .jq . Символы модуля импортируются в пространство имен вызывающего модуля так, как если бы содержимое модуля было включено непосредственно.

Необязательные метаданные должны быть выражением jq константы. Это должен быть объект с ключами, такими как homepage и т. д. В настоящее время jq использует только ключ/значение search метаданных. Метаданные также доступны пользователям через встроенную функцию modulemeta.

import RelativePathString as $NAME [<metadata>];

Импортирует JSON-файл, найденный по заданному пути относительно каталога в пути поиска. К строке относительного пути будет добавлен суффикс .json . Данные файла будут доступны как $NAME::NAME.

Необязательные метаданные должны быть выражением jq константы. Это должен быть объект с ключами, такими как homepage и т. д. В настоящее время jq использует только ключ/значение search метаданных. Метаданные также доступны пользователям через встроенную функцию modulemeta.

Ключ search в метаданных, если он присутствует, должен иметь строковое или массивно-строковое значение (массив строк); это путь поиска, который будет добавлен к верхнему уровню пути поиска.

module <metadata>;

Эта директива полностью необязательна. Она не требуется для правильной работы. Она служит только для предоставления метаданных, которые можно прочитать с помощью встроенной функции modulemeta.

Метаданные должны быть выражением jq константы. Это должен быть объект с ключами, такими как homepage. В настоящее время jq не использует эти метаданные, но они доступны пользователям через встроенную функцию modulemeta.

modulemeta

Принимает имя модуля в качестве входных данных и выводит метаданные модуля как объект, при этом импорты модуля (включая метаданные) — это значение массива для ключа deps, а определенные функции модуля — это значение массива для ключа defs.

Программы могут использовать это для запроса метаданных модуля, которые затем можно использовать для, например, поиска, скачивания и установки отсутствующих зависимостей.

Цвета

Для настройки альтернативных цветов просто установите переменную среды JQ_COLORS в список, разделенный двоеточием, частичных кодов эскейпов терминала, например, "1;31", в таком порядке:

  • цвет для null
  • цвет для false
  • цвет для true
  • цвет для чисел
  • цвет для строк
  • цвет для массивов
  • цвет для объектов
  • цвет для ключей объектов

Стандартная схема цветов такая же, как при установке JQ_COLORS="0;90:0;37:0;37:0;37:0;32:1;37:1;37:1;34".

Это не руководство по VT100/ANSI-эскейпам. Однако каждое из этих цветовых указаний должно состоять из двух чисел, разделенных точкой с запятой, где первое число — одно из следующих:

  • 1 (яркий)
  • 2 (тусклый)
  • 4 (подчёркнутый)
  • 5 (мигающий)
  • 7 (обратный)
  • 8 (скрытый)

а второе — одно из следующих:

  • 30 (чёрный)
  • 31 (красный)
  • 32 (зелёный)
  • 33 (жёлтый)
  • 34 (синий)
  • 35 (пурпурный)
  • 36 (голубой)
  • 37 (белый)

© 2012 Stephen Dolan
Licensed under the Creative Commons Attribution 3.0 license
https://jqlang.github.io/jq/manual/v1.7/index.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API