jq- опорная текущая позиция в цикле - PullRequest
0 голосов
/ 27 апреля 2018

У меня есть файл журнала с именем log.json, который отформатирован так:

{"msg": "Service starting up!"}  
{"msg": "Running a job!"}
{"msg": "Error detected!"}

И еще один файл с именем messages.json, который выглядит так:

{"msg": "Service starting up!", "out": "The service has started"}
{"msg": "Error detected!", "out": "Uh oh, there was an error!"}
{"msg": "Service stopped", "out": "The service has stopped"}

Я пытаюсь написать функцию, используя jq, которая читает оба файла, и всякий раз, когда он находит msg в log.json, который совпадает с msg в messages.json, выведите значение out в соответствующей строке в messages.json. Итак, в этом случае я надеюсь получить это как вывод:

"The service has started"
"Uh oh, there was an error!"

Самое близкое, что мне удалось сделать, это следующее:

jq --argfile a log.json --argfile b messages.json -n 'if ($a[].msg == $b[].msg) then $b[].out else empty end'

Это успешно выполняет все сравнения, которые я надеюсь сделать. Однако вместо того, чтобы печатать конкретный out, который я ищу, вместо этого он печатает каждый out всякий раз, когда оператор if возвращает true (что имеет смысл. $b[].out никогда не был переопределен, и запрашивает каждый из них). Итак, это утверждение выводит:

"The service has started"
"Uh oh, there was an error!"
"The service has stopped"
"The service has started"
"Uh oh, there was an error!"
"The service has stopped"

Итак, на данный момент мне нужен какой-то способ попросить $b[current_index].out и просто напечатать это. Есть ли способ для меня сделать это (или совершенно отдельный подход, который я могу использовать)?

1 Ответ

0 голосов
/ 28 апреля 2018

messages.json эффективно определяет словарь, поэтому давайте начнем с создания словаря JSON, который мы можем легко найти. Это удобно сделать с помощью INDEX / 2, который (в случае, если у вашего jq его нет) определяется следующим образом:

def INDEX(stream; idx_expr):
  reduce stream as $row ({};
    .[$row|idx_expr|
      if type != "string" then tojson
      else .
      end] |= $row);

Первое решение теперь просто:

INDEX($messages[]; .msg) as $dict
| inputs
| $dict[.msg]
| .out 

Предполагая, что это в program.jq, соответствующий вызов будет следующим (обратите внимание, особенно на параметр -n):

jq -n --slurpfile messages messages.json -f program.jq log.json

Выше будет напечатано null, если .msg в файле журнала нет в словаре. Чтобы отфильтровать эти нули, вы можете (например) добавить select(.) в конвейер.

Другой возможностью будет использование оригинального .msg, как в этом варианте:

INDEX($messages[]; .msg) as $dict
| inputs
| . as $in
| $dict[.msg]
| .out // $in.msg
...