Верстакфорум практиков
рекламаiprazon: приватные серверные адреса IPv4 и SOCKS5, безлимитный трафик, бесплатный тест до 2 часов
ФорумСкрипты и автоматизация

Разбор JSON в bash без установки лишнего

hexdump
hexdump
Знаток
сообщений 940
с июн
8 октября, 11:57первое сообщение

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

Пока режу grep -o и добиваю sed. Работает ровно до первого поля со скобкой внутри строки, дальше выдаёт мусор молча. Чем это заменить, оставаясь в пределах того, что уже стоит?

Борис Лапин
Борис Лапин
Знаток
сообщений 1960
с мар
15 марта, 14:14#2

Регулярками JSON не режут, это дорога в один конец: сегодня прошло, завтра в описании товара встретилась фигурная скобка и всё поехало. Раз есть python3, он и будет твоим jq.

Короткая обёртка, кладётся в ~/bin/jsn:

#!/usr/bin/env python3
import sys, json
put = sys.argv[1].split('.') if len(sys.argv) > 1 else []
d = json.load(sys.stdin)
for k in put:
    if k == '':
        continue
    d = d[int(k)] if k.isdigit() else d[k]
print(d if isinstance(d, str) else json.dumps(d, ensure_ascii=False))

Дальше в скрипте всё читается глазами:

otvet=$(curl -s https://example.org/obmen/zadanie/17)
id=$(printf '%s' "$otvet" | jsn zadanie.id)
sostoyanie=$(printf '%s' "$otvet" | jsn zadanie.sostoyanie)
echo "$id $sostoyanie"

Строк тут два десятка, ставить нечего, ломается только на битом JSON. И ломается громко, с трассировкой и ненулевым кодом возврата, что сильно лучше молчаливой пустой строки от sed.

veta_l
veta_l
Новичок
сообщений 210
с янв, второй сезон
22 августа, 17:31#3

а если полей штук десять, каждый раз новый процесс python дёргать?

linuxvsem
linuxvsem
Участник
сообщений 830
с июл
1 января, 08:48#4

veta_l, для пачки полей разбирают один раз и сразу раскладывают в переменные:

eval "$(printf '%s' "$otvet" | python3 -c '
import sys, json, shlex
d = json.load(sys.stdin)["zadanie"]
for k, v in d.items():
    if isinstance(v, (str, int, float)):
        print("J_%s=%s" % (k, shlex.quote(str(v))))
')"
echo "$J_id $J_sostoyanie"

shlex.quote тут обязателен. Без него пробел или кавычка внутри значения разнесут eval в щепки, и отлаживать это потом весело.

hexdump
hexdump
Знаток
сообщений 940
с июн
8 июня, 11:05#5

Забрал обе идеи. Обёртка легла в ~/bin, а для пачки полей поставил разбор одним заходом, разница на замере вышла показательной:

двенадцать полей из одного ответа
двенадцать полей из одного ответа

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

Борис Лапин: ломается громко, с трассировкой и ненулевым кодом возврата

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