我有一个工具可以在每一行输出JSON记录,我想用jq
处理它。
输出看起来像这样:
{"ts":"2017-08-15T21:20:47.029Z","id":"123","elapsed_ms":10}
{"ts":"2017-08-15T21:20:47.044Z","id":"456","elapsed_ms":13}
当我将此传递给jq
时,如下所示:
./tool | jq 'group_by(.id)'
...它输出错误:
jq: error (at <stdin>:1): Cannot index string with string "id"
如何让jq
处理每行JSON记录数据?
答案 0 :(得分:7)
使用--slurp
(或-s
)开关:
./tool | jq --slurp 'group_by(.id)'
输出以下内容:
[
[
{
"ts": "2017-08-15T21:20:47.029Z",
"id": "123",
"elapsed_ms": 10
}
],
[
{
"ts": "2017-08-15T21:20:47.044Z",
"id": "456",
"elapsed_ms": 13
}
]
]
...然后您可以进一步处理。例如:
./tool | jq -s 'group_by(.id) | map({id: .[0].id, count: length})'
答案 1 :(得分:3)
正如@JeffMercado指出的那样,jq处理JSON流很好,但是如果你使用group_by
,那么你必须确保它的输入是一个数组。在这种情况下,可以使用-s
命令行选项完成此操作;如果您的jq具有inputs
过滤器,那么也可以使用该过滤器与-n
选项一起完成。
如果您的jq版本为inputs
(在jq 1.5中可用),那么更好的方法是使用group_by
的以下流式变体:
# sort-free stream-oriented variant of group_by/1
# f should always evaluate to a string.
# Output: a stream of arrays, one array per group
def GROUPS_BY(stream; f): reduce stream as $x ({}; .[$x|f] += [$x] ) | .[] ;
用法示例:GROUPS_BY(inputs; .id)
请注意,您需要将此选项与-n
命令行选项一起使用。
这种流式变体有两个主要优点:
group_by/1
不同。请注意,GROUPS_BY/2
的上述定义遵循此类流式过滤器的惯例,因为它会生成流。其他变体当然是可能的。
以下说明如何节省内存。假设任务是产生.id值的频率计数。单调的解决方案是:
GROUPS_BY(inputs; .id) | [(.[0]|.id), length]
更经济,更好的解决方案是:
GROUPS_BY(inputs|.id; .) | [.[0], length]