使用jq流模式提取JSON顶层标量值无输出的问题求助
jq流模式提取顶层标量值的问题与解决方法
我需要用jq的流模式处理大体积JSON数据,提取顶层对象的对应值。示例JSON数据如下:
{ "empty": null, "name": "John Smith", "sex": "male", "age": 51, "hobbies": [ "running", "kayaking", "camping", "foraging" ] }
非流模式下提取值很简单:
$ jq ".name" sample.json "John Smith" $ jq ".age" sample.json 51 $ jq ".hobbies" sample.json [ "running", "kayaking", "camping", "foraging" ]
流模式下提取数组类型的hobbies可以成功:
$ jq -cn --stream 'fromstream(1|truncate_stream(inputs | select(.[0][0] == "hobbies")))' <sample.json ["running","kayaking","camping","foraging"]
但提取标量类型的name或age时,命令返回空结果:
$ jq -cn --stream 'fromstream(1|truncate_stream(inputs | select(.[0][0] == "name")))' <sample.json $ jq -cn --stream 'fromstream(1|truncate_stream(inputs | select(.[0][0] == "age")))' <sample.json
调试时能看到目标值已被选中,但无法输出,核心原因是标量类型在流模式下的处理逻辑和数组/对象不同。
问题根源
流模式会将JSON拆分为路径-值对的流:
- 标量值(字符串、数字、null、布尔)对应的流条目是
[["name"], "John Smith"],路径长度为1; - 数组/对象会生成多个条目,比如数组的每个元素对应
[["hobbies", 0], "running"],最后还有结束标记[["hobbies"], null]。
truncate_stream(1)会移除路径的第一层(比如去掉["hobbies"]这一层),对于数组,剩下的路径是索引,fromstream能把这些条目重新组装成数组。但对于标量,truncate_stream(1)后路径变成空数组[],对应的条目是[[],"John Smith"],而fromstream默认会忽略空路径的条目,因此无法输出标量值。
解决办法
1. 兼容标量与复杂类型的通用写法
判断选中的流条目是否为标量(路径长度为1),是则直接输出值,否则用原逻辑处理:
# 提取name jq -cn --stream 'inputs | select(.[0][0] == "name") | if .[0] | length == 1 then .[1] else fromstream(1|truncate_stream([.])) end' <sample.json # 提取age jq -cn --stream 'inputs | select(.[0][0] == "age") | if .[0] | length == 1 then .[1] else fromstream(1|truncate_stream([.])) end' <sample.json
2. 直接提取标量的简洁写法
如果确定目标是标量,可以直接匹配完整路径,输出对应的值:
jq -cn --stream 'inputs | select(.[0] == ["name"]) | .[1]' <sample.json jq -cn --stream 'inputs | select(.[0] == ["age"]) | .[1]' <sample.json
3. 支持批量提取的通用脚本
如果需要同时提取多个字段(包括标量和复杂类型),可以用以下脚本:
jq -cn --stream ' foreach inputs as $item ({}; if $item[0][0] | IN("name", "age", "hobbies") then if $item[0] | length == 1 then .[$item[0][0]] = $item[1] else .[$item[0][0]] |= fromstream(1|truncate_stream([$item])) end else . end; if $item[1] == null then .[$item[0][0]] else empty end )' <sample.json
内容的提问来源于stack exchange,提问作者enid569
相关产品推荐
相关产品推荐

