Сгенерировать JSON из данных, разделённых двоеточиями, в скрипте оболочки

Вопрос или проблема

У меня есть файл, подобный этому

103710:v2HAbAFH029324:[email protected]:localhost:Отправлено
103821:CCFE5609E3:[email protected]:localhost:Возврат
103922:DFF19609E2:[email protected]:localhost:Отложено

Мне нужно изменить это на

{"randomId":{"s":"103710"},"id":{"s":"v2HAbAFH029324"},"userId":{"s":"[email protected]"},"dns":{"s":"localhost"},"status":{"s":"Отправлено"}}
{"randomId":{"s":"103821"},"id":{"s":"CCFE5609E3"},"userId":{"s":"[email protected]"},"dns":{"s":"localhost"},"status":{"s":"возврат"}}
{"randomId":{"s":"103922"},"id":{"s":"DFF19609E2"},"userId":{"s":"[email protected]"},"dns":{"s":"localhost"},"status":{"s":"Отложено"}}

Я думаю, что код будет выглядеть так

while read line
do     
        sed -i 's/^/{"randomId":{"s":"https://unix.stackexchange.com/" test
        echo $line

        echo $line | grep -q ":"
        [ $? -eq 0 ] && echo "https://unix.stackexchange.com/"{"id":{"s":/"
        [ $? -eq 1 ] && echo "https://unix.stackexchange.com/",{"userId":{"s":/"
        [ $? -eq 2 ] && echo "https://unix.stackexchange.com/",{"host":{"s":/"
        [ $? -eq 3 ] && echo "https://unix.stackexchange.com/",{"status":{"s":/"
        echo "$line | " ";
done < test

Добавление для первого вхождения : {"id":{"s": и затем второго вхождения добавляя {"userId":{"s":

Этот блок grep/echo не сделает ничего полезного; $? будет установлен один раз — он не будет итерировать по полям.

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

while IFS=':' read -r randomid id userid dns status; do
    printf '{"randomId":{"s":"%s"},"id":{"s":"%s"},"userId":{"s":"%s"},"dns":{"s":"%s"},"status":{"s":"%s"}}\n' \
           "$randomid" "$id" "$userid" "$dns" "$status"
done

Использование printf вместо более знакомого echo избегает всех \"-последовательностей, которые потребовал бы echo. Обратите внимание на обратный слеш в конце строки для разделения.

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

С помощью perl:

perl -MJSON -F: -ple '@A = qw/randomId id userId dns status/; $_ = encode_json({map { shift @A => { "s" => $_ } } @F } )' input.csv

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

sed -r -i 's/^(.*):(.*):(.*):(.*):(.*)$/{"randomId":{"s":"\1"},"id":{"s":"\2"},"userId":{"s":"\3"},"dns":{"s":"\4"},"status":{"s":"\5"}}/' input.txt

Вы используете группы захвата, чтобы захватить все между началом файла, вашим разделителем и концом файла, а затем просто манипулируете текстом вокруг этих групп. Каждая группа захвата ссылается на “\#” где # — это номер группы захвата, начиная с одного и увеличивая на один для каждой группы.

Как уже упоминалось, вы также можете установить свой собственный разделитель. Bash имеет встроенную переменную, называемую IFS (внутренний разделитель полей). IFS по умолчанию равен пробелу, но вы можете изменить его. Я не буду показывать пример в bash, так как он уже был дан, и это просто было бы его копией.

perl -F: -pale '
   @A = qw/randomId id userId dns status/;
   ($k, $_) = (0, "{" . join(",", map qq/"$A[$k++]":{"s":"$_"}/, @F) . "}");
' ваш_файл

Объяснение

Массив @F содержит поля, разделенные на :, которые затем соединяются с соответствующей обработкой {"s":"полеI"} и предшествуют соответствующему элементу из массива @A. Все эти элементы собираются вместе с помощью join на , и заключаются в “{” … “}”. И вы закончили.

Используя Miller (mlr) для чтения данных как разделенных двоеточиями полей, добавляя требуемый ключ к каждому полю, а затем перемещая значения вниз в под-объекты с ключом s:

mlr --n2l --ifs colon --jvquoteall \
    label randomId,id,userId,dns,status затем \
    put 'for (k in $*) { $[k] = { "s": $[k] } }' файл

Здесь опция --n2l является сокращением для --inidx --ojsonl, --ifs устанавливает разделитель, а --jvquoteall заставляет Miller выводить все значения как строки (числовые данные в противном случае не будут заключены в кавычки). Глагол label устанавливает имена полей в заданный список по порядку, а выражение put итерирует по каждому полю и перемещает данные вниз в под-объект с ключом s.

Вывод:

{"randomId": {"s": "103710"}, "id": {"s": "v2HAbAFH029324"}, "userId": {"s": "[email protected]"}, "dns": {"s": "localhost"}, "status": {"s": "Отправлено"}}
{"randomId": {"s": "103821"}, "id": {"s": "CCFE5609E3"}, "userId": {"s": "[email protected]"}, "dns": {"s": "localhost"}, "status": {"s": "возврат"}}
{"randomId": {"s": "103922"}, "id": {"s": "DFF19609E2"}, "userId": {"s": "[email protected]"}, "dns": {"s": "localhost"}, "status": {"s": "Отложено"}}

Другой подход — использовать jq для чтения ввода как сырых текстовых строк, разделения каждой строки на массив отдельных строк по двоеточиям, а затем создания отдельных объектов JSON с ключом s как единственным ключом и строкой как значением этого ключа. Массив объектов затем преобразуется в объект с ключами, взятыми из аргумента командной строки --args.

jq -R -c 'split(":") | map({ s: . }) | with_entries(.key = $ARGS.positional[.key])' файл --args randomId id userId dns status

Результат:

{"randomId":{"s":"103710"},"id":{"s":"v2HAbAFH029324"},"userId":{"s":"[email protected]"},"dns":{"s":"localhost"},"status":{"s":"Отправлено"}}
{"randomId":{"s":"103821"},"id":{"s":"CCFE5609E3"},"userId":{"s":"[email protected]"},"dns":{"s":"localhost"},"status":{"s":"возврат"}}
{"randomId":{"s":"103922"},"id":{"s":"DFF19609E2"},"userId":{"s":"[email protected]"},"dns":{"s":"localhost"},"status":{"s":"Отложено"}}

Вы можете найти csvjson полезным. Пожалуйста, обратитесь к документации.

Пример команды

cat data.csv | csvjson -d :

Вывод

[{"103710": 103821.0, "v2HAbAFH029324": "CCFE5609E3", "[email protected]": "[email protected]", "localhost": "localhost", "Sent": "возврат"}, {"103710": 103922.0, "v2HAbAFH029324": "DFF19609E2", "[email protected]": "[email protected]", "localhost": "localhost", "Sent": "Отложено"}]

Установка

pip install csvkit

Пожалуйста, обратитесь к документации для получения актуальной информации.

Ответ или решение

Чтобы преобразовать данные, разделённые двоеточием, в формат JSON с использованием оболочки (shell), можно воспользоваться разными подходами. Ниже представлено несколько способов достижения желаемого результата, включая использование командной строки и языков скриптов, таких как Bash и Perl.

Метод 1: Использование Bash с read

Наиболее простым и понятным методом является использование встроенной функции read в Bash. Например:

while IFS=':' read -r randomId id userId dns status; do
    printf '{"randomId":{"s":"%s"},"id":{"s":"%s"},"userId":{"s":"%s"},"dns":{"s":"%s"},"status":{"s":"%s"}}\n' \
           "$randomId" "$id" "$userId" "$dns" "$status"
done < input.txt
  1. Что происходит в коде?
    • IFS=':' устанавливает символ разделителя на двоеточие.
    • read -r читает каждый элемент строки и присваивает их переменным randomId, id, userId, dns, status.
    • printf формирует нужный формат JSON для каждой строки и выводит результат.

Метод 2: Использование команд sed

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

sed -r 's/^(.*):(.*):(.*):(.*):(.*)$/{"randomId":{"s":"\1"},"id":{"s":"\2"},"userId":{"s":"\3"},"dns":{"s":"\4"},"status":{"s":"\5"}}/' input.txt
Пояснение:
  • Команда sed с использованием регулярных выражений (-r) захватывает каждую часть, разделённую двоеточием, и заменяет всю строку подходящим форматом JSON.

Метод 3: Использование Perl

Если вам известен Perl, вы можете использовать следующий код:

perl -MJSON -F: -ple '@A = qw/randomId id userId dns status/; $_ = encode_json({map { shift @A => { "s" => $_ } } @F } )' input.txt
Суть:
  • Этот скрипт разбивает входные данные на части и использует модуль JSON для преобразования в формат JSON.

Метод 4: Использование jq

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

jq -Rn '[(inputs | split(":")) | {"randomId": {"s": .[0]}, "id": {"s": .[1]}, "userId": {"s": .[2]}, "dns": {"s": .[3]}, "status": {"s": .[4]}}]' input.txt

Заключение

Каждый из представленных методов имеет свои преимущества в зависимости от контекста задачи и предпочтений разработчика. Bash подходит для простых задач, sed хорошо справляется с текстовыми заменами, Perl является мощным инструментом для сложных преобразований, а jq предоставляет гибкость в работе с JSON. Выбор конкретного метода зависит от ваших требований и предпочтений.

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

Оцените материал
Добавить комментарий

Капча загружается...