用 jq 解析 JSON 格式
Parsing JSON format with jq
我需要解析 lsblk
的输出。由于我是在脚本中执行此操作,因此我需要标准化格式的输出。因此我选择 JSON 格式作为输出。这是带有一些示例输出的命令:
# lsblk -o NAME,MOUNTPOINT -J
{
"blockdevices": [
{"name": "sda", "mountpoint": null,
"children": [
{"name": "sda1", "mountpoint": "/sda1/mountpoint"},
{"name": "sda2", "mountpoint": null,
"children": [
{"name": "sda2_mapper", "mountpoint": "/sda2/mountpoint"}
]
},
{"name": "sda3", "mountpoint": null},
{"name": "sda4", "mountpoint": null}
]
},
{"name": "sdb", "mountpoint": null,
"children": [
{"name": "sdb1", "mountpoint": "/sdb1/mountpoint"},
{"name": "sdb2", "mountpoint": null}
]
},
{"name": "sdc", "mountpoint": null}
]
}
我想提取所有 innermost 节点的名称,即没有子节点的所有节点的名称。上述示例的所需输出为:
sda1
sda2_mapper
sda3
sda4
sdb1
sdb2
sdc
我选择的工具是 jq
,这是我最近才发现的。我试过了
# jq '.blockdevices[].children[]?.name?'
但这只过滤了第一层的名字。我也试过
# jq 'recurse(.name?)'
但这 return 是整个文件。
有没有办法只 return 没有子节点的节点,无论它们嵌套多深?
PS:我有能力实现bash
或awk
的要求。但是,我更喜欢使用像 jq
这样的工具的解决方案,其特定目的是解析 json 个文件。
我认为这不是最简单的方法,但它似乎有效:
$ jq -r '.blockdevices[] | .. | objects | select(has("children")|not)| .name' tmp.json
sda1
sda2_mapper
sda3
sda4
sdb1
sdb2
sdc
它递归地输出在 JSON 中找到的每个值,首先过滤掉任何不是对象的东西,然后是任何具有 children
键的对象。最后,您可以 select 每个剩余对象的 name
值。
根据您的 JSON 输入,以下命令:
jq '.. | scalars'
发出 "leaves",开始:
"sda"
"sda1"
"/sda1/mountpoint"
使用 -r(原始输出)从字符串中去除引号。
我需要解析 lsblk
的输出。由于我是在脚本中执行此操作,因此我需要标准化格式的输出。因此我选择 JSON 格式作为输出。这是带有一些示例输出的命令:
# lsblk -o NAME,MOUNTPOINT -J
{
"blockdevices": [
{"name": "sda", "mountpoint": null,
"children": [
{"name": "sda1", "mountpoint": "/sda1/mountpoint"},
{"name": "sda2", "mountpoint": null,
"children": [
{"name": "sda2_mapper", "mountpoint": "/sda2/mountpoint"}
]
},
{"name": "sda3", "mountpoint": null},
{"name": "sda4", "mountpoint": null}
]
},
{"name": "sdb", "mountpoint": null,
"children": [
{"name": "sdb1", "mountpoint": "/sdb1/mountpoint"},
{"name": "sdb2", "mountpoint": null}
]
},
{"name": "sdc", "mountpoint": null}
]
}
我想提取所有 innermost 节点的名称,即没有子节点的所有节点的名称。上述示例的所需输出为:
sda1
sda2_mapper
sda3
sda4
sdb1
sdb2
sdc
我选择的工具是 jq
,这是我最近才发现的。我试过了
# jq '.blockdevices[].children[]?.name?'
但这只过滤了第一层的名字。我也试过
# jq 'recurse(.name?)'
但这 return 是整个文件。
有没有办法只 return 没有子节点的节点,无论它们嵌套多深?
PS:我有能力实现bash
或awk
的要求。但是,我更喜欢使用像 jq
这样的工具的解决方案,其特定目的是解析 json 个文件。
我认为这不是最简单的方法,但它似乎有效:
$ jq -r '.blockdevices[] | .. | objects | select(has("children")|not)| .name' tmp.json
sda1
sda2_mapper
sda3
sda4
sdb1
sdb2
sdc
它递归地输出在 JSON 中找到的每个值,首先过滤掉任何不是对象的东西,然后是任何具有 children
键的对象。最后,您可以 select 每个剩余对象的 name
值。
根据您的 JSON 输入,以下命令:
jq '.. | scalars'
发出 "leaves",开始:
"sda"
"sda1"
"/sda1/mountpoint"
使用 -r(原始输出)从字符串中去除引号。