Как конвертировать мой файл .txt в .json в bash?

У меня есть такой текстовый файл txt (где * это какой-то текст):

[ Some ping ], 1..7 pings
-----------------------------------------------------------------------------------
not ok  1  ********* ****** ******* ************ (**** ***), 6ms
not ok  2  ********* ****** ******* ************ (*** ** ** ***, *** ***), 24ms
ok  3   ********* ****** ***** (*** ** ** ***, *** ***), 21ms
ok  4  ********* ****** ******* **** (**** ***), 10ms
ok  5  ********* ****** ******* **** (*** ** ** ***, *** ***), 17ms
ok  6  ********* ****** ******* ****** (**** ***), 11ms
ok  7  ********* ****** ******* ****** (*** ** ** ***, *** ***), 28ms
-----------------------------------------------------------------------------------
5 (of 7) pings passed, 2 ping failed, percents as 61.23%, spent 127ms

Я ищу способ преобразовать это в json, как это:

{
"MainHead": Some ping",
"pings":[
{
"head": "********* ****** ******* ************ (**** ***)",
"result": false,
"time": "6ms"
},
{
"head": "********* ****** ******* ************ (*** ** ** ***, *** ***)",
"result": false,
"time": "24ms"
},
{
"head": "********* ****** ***** (*** ** ** ***, *** ***)",
"result": true,
"time": "21ms"
},
{
"head": "********* ****** ******* **** (**** ***)",
"result": true,
"time": "20ms"
},
{
"head": "********* ****** ******* **** (*** ** ** ***, *** ***)",
"result": true,
"time": "17ms"
},
{
"head": "********* ****** ******* ****** (**** ***)",
"result": true,
"time": "11ms"
},
{
"head": "********* ****** ******* ****** (*** ** ** ***, *** ***)",
"result": true,
"time": "28ms"
}
],
"total": {
"good": 5,
"bad": 2,
"percents": 61.23,
"time": "127ms"
}
}

Я пока нашел только такое решение, но оно не дает той картины которую я хочу получить.

   jq -Rs '[ split("\n")[] | select(length > 0) | split(":") | {head: .[0], result: .[1], time: .[2]} ]'  text.txt

Ответы (1 шт):

Автор решения: DiD
cat  ./text.txt | egrep '^(not|ok)' | perl -pe 's/^((not\s+)?ok)\s+(\d+)\s+([^)]+\)),\s+(\d+)ms$/{"head":"$4","result":"$1","time":$5}/g; s/"ok"/true/g; s/"not ok"/false/g' | jq -s . |  jq -n '.pings |= [inputs]' | jq ".MainHead=\"$(cat ./text.txt | egrep -m 1 -B 1 '^-{70,}' | head -1 | perl -pe 's/^\[([^]]*)\].*$/$1/')\"" | jq ".total={\"good\":$(cat ./text.txt | egrep '^ok' | wc -l),"bad":$(cat ./text.txt | egrep '^not ok' | wc -l),"percents":$(echo `cat ./text.txt | egrep '^ok' | wc -l`' / ('`cat ./text.txt | egrep '^not ok' | wc -l`' +'`cat ./text.txt | egrep '^ok' | wc -l`') * 100' | bc -l)}"
  • cat ./text.txt выводит на экран файл
  • egrep '^(not|ok)' фильтрует тело файла отсекая заголовок и конец
  • perl ... преобразует строку в почти JSON
  • далее я заменяю ok на true и not ok на false (вероятно, не самый оптимальный способ, но одноразово пойдет)
  • jq -s . делает остальную работу по формированию валидного JSON
  • второй jq обрамляет массив в объект с свойством pings
  • третий jq добавляет поле MainHead.
  • четвертый jq добавляет поле total.

Внутри третьего jq немного жёстковатый код. Параметры -m 1 и -B 1 означают только первое соответствие и затронуть одну строчку до соответствия, само регулярное выражение '^-{70,}' ищет строку где есть 70 и более дефисов от начала строки, head -1 отбирает первую строку из egrep, perl выбирает всё что в квадратных скобочках.

Внутри четвертого jq используется bc для подсчетов процентов. Сумму времени добавлю позже.

Вроде норм. Правда поле MainHead добавилось в конец JSON. У меня получился вывод:

{
  "pings": [
    [
      {
        "head": "********* ****** ******* ************ (**** ***)",
        "result": false,
        "time": 6
      },
      {
        "head": "********* ****** ******* ************ (*** ** ** ***, *** ***)",
        "result": false,
        "time": 24
      },
      {
        "head": "********* ****** ***** (*** ** ** ***, *** ***)",
        "result": true,
        "time": 21
      },
      {
        "head": "********* ****** ******* **** (**** ***)",
        "result": true,
        "time": 10
      },
      {
        "head": "********* ****** ******* **** (*** ** ** ***, *** ***)",
        "result": true,
        "time": 17
      },
      {
        "head": "********* ****** ******* ****** (**** ***)",
        "result": true,
        "time": 11
      },
      {
        "head": "********* ****** ******* ****** (*** ** ** ***, *** ***)",
        "result": true,
        "time": 28
      }
    ]
  ],
  "MainHead": " Some ping ",
  "total": {
     "good": 5,
     "bad": 2,
     "percents": 71.42857142857143
   }
}
→ Ссылка