fx — алтернатива jq для обработки JSON из командной строки / Хабр
jq — самая популярная утилита для обработки JSON из командной строки, написана на C и имеет свой собственный синтаксис для работы с JSON.
Однако, обрабатывать JSON в командной строке не нужно очень часто, а когда потребность возникает, приходится мучиться с незнакомым языком программирования.
Так и появилась идея написать fx с простым и понятным синтаксисом, который никогда не забудешь. А какой язык программирования знают все? Правильно — JavaScript.
fx принимает в качестве аргумента код на JavaScript, содержащий анонимную функцию, и вызывает её, подставляя в качестве аргумента JSON, полученный из stdin. То, что функция вернёт, будет выведено в stdout. Все. Больше никаких сложных и непонятных конструкций.
Сравните два решения одной и той же задачи на jq и на fx:
jq '[.order[] as $x | .data[$x]]'
fx 'input => input.order.map(x => obj.data[x])'
Чуть более многословно? Да, это же просто обычный JavaScript.
Если fx вообще не передать аргументов, то JSON будет отформатирован и выведен:
$ echo '{"key":"value"}' | fx { "key": "value" }
Если код не содержит param =>
, то переданный код будет автоматически преобразован в анонимную функцию и this
будет содержать переданный JSON объект:
$ echo '{"foo": [{"bar": "value"}]}' | fx 'this.foo[0].bar' "value"
fx можно передать несколько аргументов/анонимных функций, они будут применены поочерёдно к JSON:
$ echo '{"foo": [{"bar": "value"}]}' | fx 'x => x.foo' 'this[0]' 'this.bar' "value"
Если код содержит ключевое слово yield
, созданная анонимная функция будет содержать «развернутый» генератор (пример из generator-expression):
$ cat data.json | fx '\ for (let user of this) \ if (user.login.startsWith("a")) \ yield user'
$ echo '["a", "b"]' | fx 'yield* this' [ "a", "b" ]
Это позволяет описывать очень простые выборки в сложных запросах.
Кстати, модифицировать JSON с fx тоже очень просто:
$ echo '{"count": 0}' | fx '{...this, count: 1}' { "count": 1 }
А также можно использовать любой npm пакет, если поставить его глобально:
$ npm install -g lodash $ cat package.json | fx 'require("lodash").keys(this.dependencies)'
Для некоторых важно, что jq всего лишь один бинарник (~2mb). Так вот fx тоже имеет отдельные бинарники.
Весят они немного больше (~30mb), но если вам это не критично, и стоит nodejs, то поставить fx можно с помощью npm:
npm install -g fx
А что по производительности? Давайте замерим с помощью hyperfine:
$ curl 'https://api.github.com/repos/stedolan/jq/commits' > data.json $ hyperfine --warmup 3 "jq ..." "fx ..." Benchmark #1: cat data.json | jq '[.[] | {message: .commit.message, name: .commit.committer.name}]' Time (mean ± σ): 10.7 ms ± 0.9 ms [User: 8.7 ms, System: 3.6 ms] Range (min … max): 9.0 ms … 14.9 ms Benchmark #2: cat data.json | fx 'this.map(({commit}) => ({message: commit.message, name: commit.committer.name}))' Time (mean ± σ): 159.6 ms ± 4.4 ms [User: 127.4 ms, System: 28.4 ms] Range (min … max): 153.0 ms … 170.0 ms
На порядок меньше. А все дело в том, что fx использует eval
для запуска кода из аргументов (и вообще весь код fx <70 строк кода). Если для вас важна скорость обработки, не используйте fx. Во всех остальных случаях — fx отличный выбор.
- fx
- jq
Надеюсь, эта утилита кому-нибудь пригодится. Спасибо за внимание.
Электронные Сигареты JQ – Официальный сайт
В наличии
Стартовый Набор JQ Black
1200 i
Стартовый Набор JQ Black. Электронная Сигареты JQ со сменными картриджами Внешняя сторона настолько же важна, к…
В наличии
Стартовый Набор JQ Blue
1200 i
Стартовый Набор JQ Blue
Электронная Сигареты JQ со сменными картриджами
Внешняя сторона настолько же важна, как. ..
В наличии
Стартовый Набор JQ Gold
1200 i
Стартовый Набор JQ Gold Электронная Сигареты JQ со сменными картриджами Новые электронные испарители JQ голд в …
В наличии
Стартовый Набор JQ Red
1200 i
Стартовый Набор JQ Red Электронная Сигареты JQ со сменными картриджами Выделяться не стыдно. И если у вас в рук…
В наличии
349 i
Капсулы JQ со вкусом спелого Арбуза (2шт) Одними из наиболее популярных и востребованных линеек будут оставаться фру…
В наличии
Капсулы JQ Банан
349 i
Капсулы JQ со вкусом Банан (2шт) Мы не создаем новые тренды. Мы задаем им новые планки качества. Подтверждением этог…
В наличии
Капсулы JQ Виноград-мята
349 i
Капсулы JQ со вкусом Винограда и Мята (2шт)
Рынок вкусов для электронных испарителен настолько большой, что сочетани. ..
В наличии
Капсулы JQ Вишня
349 i
Капсулы JQ со вкусом Вишни (2шт) Новые технологи, новый взгляд, новые фруктовые вкусы. Сменные капсулы JQ «Вишня» …
В наличии
Капсулы JQ Дыня349 i
Капсулы JQ со вкусом Дыни (2шт) Мы используем другие формулы, которые отличаются от тех, которые вы привыкли видеть …
В наличии
Капсулы JQ Классик
350 i
Капсулы JQ (2шт) Мы хотим показать вам новый взгляд на то, какие вкусовые ощущение у вас могут вызывать электронные …
В наличии
Капсулы JQ Кофе
349 i
Капсулы JQ со вкусом Кофе (2шт) Энергичный заряд бодрости можно передать не только посредством чашки кофе. Спасибо 2…
В наличии
Капсулы JQ Лесные Ягоды
349 i
Капсулы JQ со вкусом Лесных Ягод (2шт)
Эксперименты с фруктовыми миксами иногда дают плодотворные результаты. Именно…
В наличии
Капсулы JQ Манго-Айс
349 i
Капсулы JQ со вкусом Манго-Айс (2шт) Мы любим экзотику ровно также, как и вы. Эта любовь послужила мотивом для того,…
В наличии
Капсулы JQ Мята
349 i
Капсулы JQ со вкусом Освежающей Мяты (2шт) Существует категория покупателей, которые приобретают фруктовые и другие …
В наличии
Капсулы JQ Черная смородина-мята
349 i
Капсулы JQ со вкусом Черной смородины и Мяты (2шт) Фруктовые и ягодные вкусы хорошо сочетаются с мятой. Сегодня можн…
В наличии
Капсулы JQ Яблоко
349 i
Капсулы JQ со вкусом Яблоко (2шт) Не обязательно искать компромиссы, когда вы просто хотите увидеть в своей коллекци…
Скачать jq
jq написан на C и не имеет зависимостей во время выполнения, поэтому он должен быть
можно построить его практически для любой платформы.
Двоичные файлы должны просто запускаться, но в OS X и Linux вам может понадобиться
чтобы сначала сделать их исполняемыми, используя chmod +x jq
.
jq находится под лицензией MIT. Для всей крови
подробности читайте в файле COPYING
в исходниках дистрибутива.
jq использует библиотеку C для поддержки десятичных чисел. Это реанимация 1.8.1 лицензионный код, полученный из архива загрузок ICU http://download.icu-project.org/files/decNumber/decNumber-icu-368.zip.
Линукс
jq 1.5 есть в официальном Debian и Репозитории Убунту. Установить с помощью
sudo apt-get install jq
.jq 1.5 есть в официалке Репозиторий Федоры. Установите с помощью
.jq 1.4 есть в официальном openSUSE репозиторий. Установите с помощью
sudo zypper install jq
.jq 1.5 есть в официалке Арка репозиторий. Установить с помощью
sudo pacman -S jq
.бинарных файла jq 1.6 для 64-битный или же 32-бит.
бинарных файла jq 1.5 для 64-битный или же 32-бит.
бинарных файла jq 1.4 для 64-битный или же 32-бит.
бинарных файла jq 1.3 для 64-битный или же 32-бит.
ОС Х
Используйте Homebrew для установки jq 1.6 с
варить установить jq
.Используйте MacPorts для установки jq 1.6 с
порт установить jq
.jq 1.6 бинарник для 64-бит.
jq 1.5 бинарный для 64-бит.
бинарных файла jq 1.4 для 64-битный или же 32-бит.
бинарных файла jq 1.3 для 64-битный или же 32-бит.
FreeBSD
Солярис
pkgutil -i jq
в OpenCSW для Solaris 10+, Sparc и x86.двоичных файла jq 1.4 для Solaris 11 64-битный или же 32-бит.
Окна
Используйте Chocolatey NuGet для установки jq 1.5 с
шоколадный установить jq
.исполняемых файла jq 1.6 для 64-битный или же 32-бит.
исполняемых файла jq 1.5 для 64-битный или же 32-бит.
исполняемых файла jq 1.4 для 64-битный или же 32-бит.
исполняемых файла jq 1.3 для 64-битный или же 32-бит.
Контрольные суммы и подписи
Контрольные суммы SHA-256 предоставляются для всех выпускных и предварительных двоичных файлов. Их можно найти под sig/v1.x/sha256sum.txt. Контрольные суммы для jq 1.6 находятся в sig/v1.6/sha256sum.txt. Контрольные суммы для jq 1.5 находятся в sig/v1.5/sha256sum.txt.
Кроме того, все двоичные файлы подписаны
Ключ подписи пакета jq.
Подписи можно найти в разделе
сиг/v1. x/*.asc.
Подписи для jq 1.6 находятся в
знак/v1.5/*.asc.
Подписи для jq 1.5 находятся в
знак/v1.5/*.asc.
Вы можете использовать GnuPG для проверки подписи, загрузив
подпись и бег
gpg --проверить подпись.asc
.
Из исходного кода для Linux, OS X, Cygwin и других POSIX-подобных операционных систем
- Архив с исходным кодом для jq 1.6
- Архив исходников для jq 1.5
Вы можете собрать его с помощью обычного ./configure && make && sudo
make install
вздор.
Если вы заинтересованы в использовании последней версии разработки, попробуйте:
git clone https://github.com/stedolan/jq.git компакт-диск JQ автореконф -я ./configure --disable-maintainer-mode делать судо сделать установить
Чтобы собрать его из клона git, вам нужно установить несколько пакеты сначала:
- GCC
- Сделать
- Автоинструменты
Для систем Linux все это будет в пакете вашей системы
менеджер, и если вы делаете разработку на машине, они больше всего
скорее всего уже установлен.
В OS X все они включены в инструменты командной строки Apple, которые могут быть установлен из Xcode. Однако, вы можете обнаружить, что вам нужна более новая версия Bison, чем предоставленная Apple. Это можно найти в Homebrew или MacPorts.
Флаг --disable-maintainer-mode
говорит использовать предварительно сгенерированный лексер
и парсер, который поставляется с кодом. Для компиляции лексера и парсера также
из источника, оставьте этот флаг. Вам нужно будет установить
Flex и
Бизон.
Создание документации
Документация jq скомпилирована в статический HTML с помощью Python.
Чтобы собрать документы, запустите pipenv, запустите python3 build_website.py
из
документы / подкаталог. Чтобы обслуживать их локально, вы можете запустить python3 -m SimpleHTTPServer
. Вам понадобится несколько зависимостей Python,
который можно установить, следуя инструкциям в docs/README.md
.
Справочная страница создается с помощью make jq.
или просто 1
make
, также из
документы YAML, и вам все равно понадобятся зависимости Python для
построить справочную страницу.
Tutorial
У GitHub есть JSON API, так что давайте поэкспериментируем с ним. Этот URL дает нам последний 5 коммитов из репозитория jq.
завиток 'https://api.github.com/repos/stedolan/jq/commits?per_page=5'
Показать результат
[ { "ша": "d25341478381063d1c76e81b3a52e0592a7c997f", "совершить": { "автор": { "name": "Стивен Долан", "электронная почта": "[email protected]", "дата": "2013-06-22T16:30:59Z" }, "коммиттер": { "name": "Стивен Долан", "электронная почта": "[email protected]", "дата": "2013-06-22T16:30:59Z" }, "message": "Запрос на слияние #162 из stedolan/utf8-fixes\n\nИсправления Utf8. Закрывается #161", "дерево": { "ша": "6ab697a8dfb5a96e124666bf6d6213822599fb40", "url": "https://api.github.com/repos/stedolan/jq/git/trees/6ab697a8dfb5a96e124666bf6d6213822599fb40" }, "url": "https://api.github.com/repos/stedolan/jq/git/commits/d25341478381063d1c76e81b3a52e0592a7c997f", "количество_комментариев": 0 }, "url": "https://api.github.com/repos/stedolan/jq/commits/d25341478381063d1c76e81b3a52e0592a7c997f", "html_url": "https://github.com/stedolan/jq/commit/d25341478381063d1c76e81b3a52e0592a7c997f", "comments_url": "https://api.github.com/repos/stedolan/jq/commits/d25341478381063d1c76e81b3a52e0592a7c997f/комментарии", "автор": { "логин": "стедолан", ...
GitHub возвращает красиво отформатированный JSON. Для серверов, которые этого не делают, это может быть
полезно передать ответ через jq, чтобы распечатать его красиво. Простейший
jq — это выражение .
, который принимает ввод и производит его
без изменений в качестве вывода.
curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | jq '.'
Показать результат
[ { "ша": "d25341478381063d1c76e81b3a52e0592a7c997f", "совершить": { "автор": { "name": "Стивен Долан", "электронная почта": "[email protected]", "дата": "2013-06-22T16:30:59Z" }, "коммиттер": { "name": "Стивен Долан", "электронная почта": "[email protected]", "дата": "2013-06-22T16:30:59Z" }, "message": "Запрос на слияние #162 из stedolan/utf8-fixes\n\nИсправления Utf8. Закрывается #161", "дерево": { "ша": "6ab697a8dfb5a96e124666bf6d6213822599fb40", "url": "https://api.github.com/repos/stedolan/jq/git/trees/6ab697a8dfb5a96e124666bf6d6213822599fb40" }, "url": "https://api.github.com/repos/stedolan/jq/git/commits/d25341478381063d1c76e81b3a52e0592a7c997f", "количество_комментариев": 0 }, "url": "https://api.github.com/repos/stedolan/jq/commits/d25341478381063d1c76e81b3a52e0592a7c997f", "html_url": "https://github.com/stedolan/jq/commit/d25341478381063d1c76e81b3a52e0592a7c997f", "comments_url": "https://api.github.com/repos/stedolan/jq/commits/d25341478381063d1c76e81b3a52e0592a7c997f/comments", "автор": { "логин": "стедолан", ...
Мы можем использовать jq для извлечения только первого коммита.
curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | jq '.[0]'
Показать результат
{ "ша": "d25341478381063d1c76e81b3a52e0592a7c997f", "совершить": { "автор": { "name": "Стивен Долан", "электронная почта": "[email protected]", "дата": "2013-06-22T16:30:59Z" }, "коммиттер": { "name": "Стивен Долан", "электронная почта": "[email protected]", "дата": "2013-06-22T16:30:59З" }, "message": "Запрос на слияние #162 из stedolan/utf8-fixes\n\nИсправления Utf8. Закрывается #161", "дерево": { "ша": "6ab697a8dfb5a96e124666bf6d6213822599fb40", "url": "https://api.github.com/repos/stedolan/jq/git/trees/6ab697a8dfb5a96e124666bf6d6213822599fb40" }, "url": "https://api.github.com/repos/stedolan/jq/git/commits/d25341478381063d1c76e81b3a52e0592a7c997f", "количество_комментариев": 0 }, "url": "https://api.github.com/repos/stedolan/jq/commits/d25341478381063d1c76e81b3a52e0592a7c997f", "html_url": "https://github.com/stedolan/jq/commit/d25341478381063d1c76e81b3a52e0592a7c997f", "comments_url": "https://api.github.com/repos/stedolan/jq/commits/d25341478381063d1c76e81b3a52e0592a7c997f/comments", "автор": { "логин": "стедолан", "идентификатор": 79765, "avatar_url": "https://avatars.githubusercontent.com/u/79765?v=3", "gravatar_id": "", "url": "https://api.github.com/users/stedolan", "html_url": "https://github.com/stedolan", "followers_url": "https://api.github.com/users/stedolan/followers", "following_url": "https://api.github.com/users/stedolan/following{/other_user}", "gists_url": "https://api.github.
com/users/stedolan/gists{/gist_id}", "starred_url": "https://api.github.com/users/stedolan/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/stedolan/subscriptions", "organizations_url": "https://api.github.com/users/stedolan/orgs", "repos_url": "https://api.github.com/users/stedolan/repos", "events_url": "https://api.github.com/users/stedolan/events{/privacy}", "received_events_url": "https://api.github.com/users/stedolan/received_events", "тип": "Пользователь", "сайт_админ": ложь }, "коммиттер": { "логин": "стедолан", "идентификатор": 79765, "avatar_url": "https://avatars.githubusercontent.com/u/79765?v=3", "gravatar_id": "", "url": "https://api.github.com/users/stedolan", "html_url": "https://github.com/stedolan", "followers_url": "https://api.github.com/users/stedolan/followers", "following_url": "https://api.github.com/users/stedolan/following{/other_user}", "gists_url": "https://api.github.
com/users/stedolan/gists{/gist_id}", "starred_url": "https://api.github.com/users/stedolan/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/stedolan/subscriptions", "organizations_url": "https://api.github.com/users/stedolan/orgs", "repos_url": "https://api.github.com/users/stedolan/repos", "events_url": "https://api.github.com/users/stedolan/events{/privacy}", "received_events_url": "https://api.github.com/users/stedolan/received_events", "тип": "Пользователь", "сайт_админ": ложь }, "родители": [ { "ша": "54b9c9bdb225af5d886466d72f47eafc51acb4f7", "url": "https://api.github.com/repos/stedolan/jq/commits/54b9c9bdb225af5d886466d72f47eafc51acb4f7", "html_url": "https://github.com/stedolan/jq/commit/54b9c9bdb225af5d886466d72f47eafc51acb4f7" }, { "ша": "8b1b503609c161fea4b003a7179b3fbb2dd4345a", "url": "https://api.github.com/repos/stedolan/jq/commits/8b1b503609c161fea4b003a7179b3fbb2dd4345a", "html_url": "https://github.
com/stedolan/jq/commit/8b1b503609c161fea4b003a7179b3fbb2dd4345a" } ] }
В остальных примерах я не буду использовать команду curl
— это не так.
собирается измениться.
Там много информации, которая нам не нужна, поэтому мы ограничим ее в самые интересные области.
jq '.[0] | {сообщение: .commit.message, имя: .commit.committer.name}'
Показать результат
{ "message": "Запрос на слияние #162 из stedolan/utf8-fixes\n\nИсправления Utf8. Закрывается #161", "name": "Стивен Долан" }
| Оператор
в jq передает вывод одного фильтра ( .[0]
, который получает
первый элемент массива в ответе) на вход другого
( {...}
, который создает объект из этих полей). Вы можете получить доступ
вложенные атрибуты, такие как .commit.message
.
Теперь займемся остальными коммитами.
jq '.[] | {сообщение: .commit.message, имя: .commit.committer.name}'
Показать результат
{ "message": "Запрос на слияние #162 из stedolan/utf8-fixes\n\nИсправления Utf8. Закрывается #161", "name": "Стивен Долан" } { "message": "Отклонить все чрезмерно длинные последовательности UTF8.", "name": "Стивен Долан" } { "message": "Исправить различные ошибки синтаксического анализа UTF8.\n\nВ частности, разобрать неверный код UTF8, заменив битые биты на U+FFFD\nи правильно выполнить ресинхронизацию после поврежденных последовательностей.", "name": "Стивен Долан" } { "message": "Исправить пример в руководстве для `floor`. См. #155.", "name": "Стивен Долан" } { "message": "Документ пол", "name": "Николас Уильямс" }
.[]
возвращает каждый элемент массива, возвращаемый в ответе, по одному за
время, которое все подается в {сообщение: .commit.message, имя: .commit.committer.name}
.
Данные в jq представлены в виде потоков значений JSON — каждый jq
выражение выполняется для каждого значения в его входном потоке и может
производить любое количество значений в свой выходной поток.
Потоки сериализуются путем простого разделения значений JSON с помощью
пробел. Это дружественный формат cat
— вы можете просто присоединиться
два потока JSON вместе и получить действительный поток JSON.
Если вы хотите получить вывод в виде единого массива, вы можете указать jq «соберите» все ответы, обернув фильтр квадратом скобки:
jq '[.[] | {сообщение: .commit.message, имя: .commit.committer.name}]'
Показать результат
[ { "message": "Запрос на слияние #163 из stedolan/utf8-fixes\n\nИсправления Utf8. Закрывается #161", "name": "Стивен Долан" }, { "message": "Отклонить все чрезмерно длинные последовательности UTF8.", "name": "Стивен Долан" }, { "message": "Исправить различные ошибки синтаксического анализа UTF8.\n\nВ частности, разобрать неверный код UTF8, заменив битые биты на U+FFFD\nи правильно выполнить ресинхронизацию после поврежденных последовательностей.", "name": "Стивен Долан" }, { "message": "Исправить пример в руководстве для `floor`. См. #155.", "name": "Стивен Долан" }, { "message": "Этаж документов", "name": "Николас Уильямс" } ]
Теперь попробуем получить URL-адреса родительских коммитов из А также результаты API. В каждом коммите GitHub API включает информацию о «родительских» коммитах. Может быть один или много.
"родители": [ { "ша": "54b9c9bdb225af5d886466d72f47eafc51acb4f7", "url": "https://api.github.com/repos/stedolan/jq/commits/54b9c9bdb225af5d886466d72f47eafc51acb4f7", "html_url": "https://github.com/stedolan/jq/commit/54b9c9bdb225af5d886466d72f47eafc51acb4f7" }, { "ша": "8b1b503609c161fea4b003a7179b3fbb2dd4345a", "url": "https://api.github.com/repos/stedolan/jq/commits/8b1b503609c161fea4b003a7179b3fbb2dd4345a", "html_url": "https://github.com/stedolan/jq/commit/8b1b503609c161fea4b003a7179b3fbb2dd4345a" } ]
Мы хотим извлечь все поля «html_url» внутри этого массива родительского
коммитов и составить простой список строк, которые будут сопровождать
Поля «сообщение» и «автор» у нас уже есть.
jq '[.[] | {сообщение: .commit.message, имя: .commit.committer.name, родители: [.parents[].html_url]}]'
Показать результат
[ { "message": "Запрос на слияние #162 из stedolan/utf8-fixes\n\nИсправления Utf8. Закрывается #161", "name": "Стивен Долан", "родители": [ "https://github.com/stedolan/jq/commit/54b9c9bdb225af5d886466d72f47eafc51acb4f7", "https://github.com/stedolan/jq/commit/8b1b503609c161fea4b003a7179b3fbb2dd4345a" ] }, { "message": "Отклонить все чрезмерно длинные последовательности UTF8.", "name": "Стивен Долан", "родители": [ "https://github.com/stedolan/jq/commit/ff48bd6ec538b01d1057be8e93b94eef6914e9ef" ] }, { "message": "Исправить различные ошибки синтаксического анализа UTF8.\n\nВ частности, разобрать неверный код UTF8, заменив битые биты на U+FFFD\nи правильно выполнить ресинхронизацию после поврежденных последовательностей.", "name": "Стивен Долан", "родители": [ "https://github.