JSON pipes в шелле
Чем больше я пишу однострочники в шелле, тем больше я прихожу к двум важным идеям: Это очень мощное средство для «непосредственного программирования», то есть указания компьютеру, что делать. Большая часть однострочника посвящена grep/awk/cut/tr, которые каким-то образом выковыривают и приводят в человеческий вид вывод предыдущих утилит. При том, что модель pipe’ов восхитительна, совершенно грязные хаки по отлову нужных полей в выводе во втором пункте («а вот тут мы можем выделить нужное нам по характерной запятой с помощью awk -F, '{print $2}'…) делают процедуру спорной по удовольствию, и уж точно нечитаемой.Ещё одна серьёзная проблема: при том, что шелл даёт довольно много идиом из функционального программирования, в нём нет идиомы фильтрации списка по результату выполнения внешней программы. То есть «грепнуть» список мы можем. А вот оставить в списке только те элементы, для которых какая-то программа вернула «успех» — нет.
При этом есть враждебная и не очень хорошо написанная среда — powershell (винды). В которых взяли хорошую идею (пайпы передают не текст, а объекты), но испортили её двумя вещами:
Неэргономичной консолью виндов (Shift-PgUp где, а?) предложением пойти и выучить .net для того, чтобы нормально с методами работать. Хочется иметь объекты в пайпе в тёплом ламповом линуксовом шелле. С hand-candy (мало печатать), eye-candy (приятно смотреть) и общей эргономичностью процесса использования. Ещё хочется иметь возможность сочетать «новый подход» со старым, то есть обычным текстовым pipe’ом.
Надо написать набор инструментов, которые позволят в pipe-style оперировать с структурированными данными. Очевидным выбором является XML JSON.Нам нужно: Утилиты, которые примут типовые форматы на вход и сконвертируют их в json. Утилиты, которые позволят в pipe’е манипулировать с json’ом. Утилиты, которые приведут json в «обычный» формат. В этом случае человек не будет видеть json на экране, но будет иметь возможность работать с ним. (для понимания я буду писать длинные имена утилит, в реальной жизни это будут короткие сокращения, то есть не json-get-object, а что-то типа jgo или jg)Выводит только файлы, для которых file сумел определить тип: ls -la | ls2json | json-filter 'filename' --exec 'file {} >/dev/null' | json-print
Выкачивает с некоторого сайта токен для авторизации, выковыривает его из json’а и выставляет в переменные среды окружения, после чего скачивает список и отфильтровав по регэкспу поле «автор» выкачивает все url’ы: curl mysite/api.json | env `json-get-to-env X-AUTH-TOKEN`; curl -H X-AUTH-TOKEN $X-AUTH-TOKEN mysite/api/list.json | json-filter --field 'author' --rmatch 'R.{1,2}dal\d*' | json-get --field 'url' | xargs wget
Парсит вывод find -ls, сортирует по полю size, вырезает из массива элементы с 10 по 20, выводит их в csv.find. -ls | ls2josn | json-sort --field 'size' | json-slice [10:20] | json2csv
input’ы Основная задача — из messy-вывода сделать json-конфетку. Важно: иметь опцию для обработки некорректного ввода: а) игнорировать, б) останавливать pipe с ошибкой.Примеры: Generic:
line2json — конвертирует обычный вывод в массив строк, где строка соответствует строке (line to string). words2json — аналогично, но по «словам». csv2json — конвертирует cvs в объект, позволяя указанный элемент назначить ключом. lineparse2json — конвертирует строку в объект, разделяя её по указанным символам. Напоминает awk -F: '{print $1, $2}', app-specific:
ls2json (на выбор — либо делает ls, либо берёт вывод ls) и структурирует его как массив объектов, где каждый объект — файл с кучей полей. Может быть, даже большей, чем умеет ls (обычные и расширенные атрибуты lsattr, вся информация про иноды, даты создания и т.д.) ps2json — аналогично, по спискам процессов lsof2json — список объектов, описывающих приложения, использующие файл. openfiles2json — список fd, открытых приложением (/proc/PID/fd), с встроенной фильтрацией, например, «files only», «ignore /dev/null». В объектах по сетевым сокетам сразу же прилагается вся информация — порты/ip. iptables2json — выводит текущие настройки iptables в форме json File-specific: Читают файл, выводят его в json’е.syslog2json ini2json conf.d2json sysv2json, upstart2json нативные json-преобразования Самое вкусное — нативные манипуляции над json’ом. Аналогично, должны иметь опции обработки «не json’а — «игнорировать»/«останавливаться». json-filter — фильтрует объекты/массивы по заданным критериям. json-join — делает из двух json’ов один указанным методом. json-sort — сортирует массив объектов по указанному полю json-slice — вырезает кусочек из массива json-arr-get — возвращает элемент из массива json-obj-get — возвращает заданное поле/поля указанного объекта json-obj-add — добавляет объект json-obj-del — удаляет объект json-obj-to-arr — выводит ключи или заданное поле объектов как массив json-arr-to-obj — превращает массив в объект формируя ключ по заданному признаку. json-uniq — удаляет повторяющиеся элементы в массиве (или выводит только повторяющиеся) (добавить по вкусу и потребностям)output’ы Приводят json в человекочитаемый вид: json2fullpath — превращают json в нотацию строк вида key1.key2[3].key4 = «foobar» json2csv json2lines — выводят массив по элементу на строку, если внутри объекты — разделяя их пробелами на строке. json2keys — выводит ключи объекта json2values — выводит только значения объекта iterator’ы Фактически, расширение xargs на json: json-keys-iterate — запускает указанные команды для каждого ключа json-values-iterate — запускает указанные команды для каждого ключа json-iterate — запускает указанные команды для каждого элемента Разумеется, такими методами невозможно решить проблему обработки произвольного json’а — он может оказаться слишком «неструктурированным». Но во-первых input’ы делают таки предсказуемый вид json’а, а во-вторых, обработка json’а всё-таки более предсказуема, чем обработка «типа тут пробелами элементы разделяются» в существующем шелле. Я бы сам написал, но часть нужного я не знаю, на что-то мне не хватает времени. Не программист, я. Тайной мыслью статьи является, что «кто-то напишет за меня», но если такого не найдётся, то останется хотя бы программная статья с мотивацией доучить (ся) и сделать самому.Если кто-то готов за подобное взяться — буду крайне благодарен. Если нет, буду свой фиговый питон расчехлять — и идеи и предложения приветствуются.