从另一个深度的另一个文件中检索一个键值
Retrieve one key value from another file at another depth
我有两个 json 文件(这些来自 AWS)。一个是在服务器状态更改 (state.json) 后从亚马逊返回的,另一个包含实例的详细信息,包括特定标签(标签称为“名称”,值包含服务器的主机名)- 文件是在我的示例中称为 instance.json。我正在尝试编写一些 jq,它使用从状态中检索到的 instanceID 来查询实例详细信息文档(使用相同的 instanceID 键)。我想如果我能在正确的位置将主机名标签添加到状态文档中,那将是理想的...
这通常是我可能能够做到的,但是键在 json 中的深度不同,我不知道如何检索不同的 depth/matching 键。 (如果您熟悉 aws,您会知道服务器状态在实例中也是 also,但是我正在更改状态并且不希望进行 3 次亚马逊调用)。
下面的一些示例 json:
instance.json(文件很大,我把无用的部分都删掉了,结构保持不变):
{
"Reservations": [
{
"Instances": [
{
"InstanceId": "i-1",
"Tags": [
{
"Value": "hostname1",
"Key": "Name"
}
],
"AmiLaunchIndex": 0
}
],
"ReservationId": "r-1",
"Groups": []
},
{
"Instances": [
{
"InstanceId": "i-2",
"Tags": [
{
"Value": "hostname2",
"Key": "Name"
}
],
"AmiLaunchIndex": 0
}
],
"ReservationId": "r-1",
"Groups": []
},
{
"Instances": [
{
"InstanceId": "i-3",
"Tags": [
{
"Value": "hostname3",
"Key": "Name"
}
],
"AmiLaunchIndex": 0
}
],
"ReservationId": "r-1",
"Groups": []
}
]
}
state.json:
{
"StoppingInstances": [
{
"CurrentState": {
"Code": 80,
"Name": "stopped"
},
"InstanceId": "i-1",
"PreviousState": {
"Code": 80,
"Name": "stopped"
}
},
{
"CurrentState": {
"Code": 80,
"Name": "stopped"
},
"InstanceId": "i-2",
"PreviousState": {
"Code": 80,
"Name": "stopped"
}
},
{
"CurrentState": {
"Code": 80,
"Name": "stopped"
},
"InstanceId": "i-3",
"PreviousState": {
"Code": 80,
"Name": "stopped"
}
}
]
}
理想的输出(如果可能):
{
"StoppingInstances": [
{
"CurrentState": {
"Code": 80,
"Name": "stopped"
},
"InstanceId": "i-1",
"Hostname": "hostname1",
"PreviousState": {
"Code": 80,
"Name": "stopped"
}
},
{
"CurrentState": {
"Code": 80,
"Name": "stopped"
},
"InstanceId": "i-2",
"Hostname": "hostname2",
"PreviousState": {
"Code": 80,
"Name": "stopped"
}
},
{
"CurrentState": {
"Code": 80,
"Name": "stopped"
},
"InstanceId": "i-3",
"Hostname": "hostname3",
"PreviousState": {
"Code": 80,
"Name": "stopped"
}
}
]
}
要根据与 state.json
共享的 ID 查询 instance.json
中的特定标签,您可以通过使用变量和 select
函数比较它们的公共 ID 来遍历目标。
jq -r --argfile state state.json --arg tag "Name" '
$state.StoppingInstances[].InstanceId as $id
| .Reservations[].Instances[]
| select(.InstanceId == $id).Tags[]
| select(.Key == $tag).Value
' instance.json
hostname1
hostname2
hostname3
要将 instance.json
中的记录与 state.json
中的项目合并,您可以使用 INDEX
和 JOIN
内置函数:
jq --argfile instance instance.json '
.StoppingInstances |= JOIN(
INDEX($instance.Reservations[].Instances[]; .InstanceId); .InstanceId
)
' state.json
{
"StoppingInstances": [
[
{"CurrentState":{"Code":80,"Name":"stopped"},"InstanceId":"i-1","PreviousState":{"Code":80,"Name":"stopped"}},
{"InstanceId":"i-1","Tags":[{"Value":"hostname1","Key":"Name"}],"AmiLaunchIndex":0}
],
[
{"CurrentState":{"Code":80,"Name":"stopped"},"InstanceId":"i-2","PreviousState":{"Code":80,"Name":"stopped"}},
{"InstanceId":"i-2","Tags":[{"Value":"hostname2","Key":"Name"}],"AmiLaunchIndex":0}
],
[
{"CurrentState":{"Code":80,"Name":"stopped"},"InstanceId":"i-3","PreviousState":{"Code":80,"Name":"stopped"}},
{"InstanceId":"i-3","Tags":[{"Value":"hostname3","Key":"Name"}],"AmiLaunchIndex":0}
]
]
}
这是一个直接使用 INDEX
的方法。它假定调用以下形式,当然可能有不同的变化:
jq -n --argfile state state.json --argfile instance instance.json -f program.jq
其中 program.jq 包含:
INDEX($instance.Reservations[].Instances[]; .InstanceId)
| map_values(.Tags|from_entries.Name) as $dict
| $state
| .StoppingInstances |= map(. + {Hostname: $dict[.InstanceId]})
如果您不确定.InstanceId在instance.json中的位置,您可以修改上面的内容如下:
INDEX($instance | .. | objects | select(has("Instances")) | .Instances[];
.InstanceId)
| map_values(.Tags|from_entries.Name) as $dict
| $state
| .StoppingInstances |= map(. + {Hostname: $dict[.InstanceId]})
我有两个 json 文件(这些来自 AWS)。一个是在服务器状态更改 (state.json) 后从亚马逊返回的,另一个包含实例的详细信息,包括特定标签(标签称为“名称”,值包含服务器的主机名)- 文件是在我的示例中称为 instance.json。我正在尝试编写一些 jq,它使用从状态中检索到的 instanceID 来查询实例详细信息文档(使用相同的 instanceID 键)。我想如果我能在正确的位置将主机名标签添加到状态文档中,那将是理想的...
这通常是我可能能够做到的,但是键在 json 中的深度不同,我不知道如何检索不同的 depth/matching 键。 (如果您熟悉 aws,您会知道服务器状态在实例中也是 also,但是我正在更改状态并且不希望进行 3 次亚马逊调用)。
下面的一些示例 json:
instance.json(文件很大,我把无用的部分都删掉了,结构保持不变):
{
"Reservations": [
{
"Instances": [
{
"InstanceId": "i-1",
"Tags": [
{
"Value": "hostname1",
"Key": "Name"
}
],
"AmiLaunchIndex": 0
}
],
"ReservationId": "r-1",
"Groups": []
},
{
"Instances": [
{
"InstanceId": "i-2",
"Tags": [
{
"Value": "hostname2",
"Key": "Name"
}
],
"AmiLaunchIndex": 0
}
],
"ReservationId": "r-1",
"Groups": []
},
{
"Instances": [
{
"InstanceId": "i-3",
"Tags": [
{
"Value": "hostname3",
"Key": "Name"
}
],
"AmiLaunchIndex": 0
}
],
"ReservationId": "r-1",
"Groups": []
}
]
}
state.json:
{
"StoppingInstances": [
{
"CurrentState": {
"Code": 80,
"Name": "stopped"
},
"InstanceId": "i-1",
"PreviousState": {
"Code": 80,
"Name": "stopped"
}
},
{
"CurrentState": {
"Code": 80,
"Name": "stopped"
},
"InstanceId": "i-2",
"PreviousState": {
"Code": 80,
"Name": "stopped"
}
},
{
"CurrentState": {
"Code": 80,
"Name": "stopped"
},
"InstanceId": "i-3",
"PreviousState": {
"Code": 80,
"Name": "stopped"
}
}
]
}
理想的输出(如果可能):
{
"StoppingInstances": [
{
"CurrentState": {
"Code": 80,
"Name": "stopped"
},
"InstanceId": "i-1",
"Hostname": "hostname1",
"PreviousState": {
"Code": 80,
"Name": "stopped"
}
},
{
"CurrentState": {
"Code": 80,
"Name": "stopped"
},
"InstanceId": "i-2",
"Hostname": "hostname2",
"PreviousState": {
"Code": 80,
"Name": "stopped"
}
},
{
"CurrentState": {
"Code": 80,
"Name": "stopped"
},
"InstanceId": "i-3",
"Hostname": "hostname3",
"PreviousState": {
"Code": 80,
"Name": "stopped"
}
}
]
}
要根据与 state.json
共享的 ID 查询 instance.json
中的特定标签,您可以通过使用变量和 select
函数比较它们的公共 ID 来遍历目标。
jq -r --argfile state state.json --arg tag "Name" '
$state.StoppingInstances[].InstanceId as $id
| .Reservations[].Instances[]
| select(.InstanceId == $id).Tags[]
| select(.Key == $tag).Value
' instance.json
hostname1
hostname2
hostname3
要将 instance.json
中的记录与 state.json
中的项目合并,您可以使用 INDEX
和 JOIN
内置函数:
jq --argfile instance instance.json '
.StoppingInstances |= JOIN(
INDEX($instance.Reservations[].Instances[]; .InstanceId); .InstanceId
)
' state.json
{
"StoppingInstances": [
[
{"CurrentState":{"Code":80,"Name":"stopped"},"InstanceId":"i-1","PreviousState":{"Code":80,"Name":"stopped"}},
{"InstanceId":"i-1","Tags":[{"Value":"hostname1","Key":"Name"}],"AmiLaunchIndex":0}
],
[
{"CurrentState":{"Code":80,"Name":"stopped"},"InstanceId":"i-2","PreviousState":{"Code":80,"Name":"stopped"}},
{"InstanceId":"i-2","Tags":[{"Value":"hostname2","Key":"Name"}],"AmiLaunchIndex":0}
],
[
{"CurrentState":{"Code":80,"Name":"stopped"},"InstanceId":"i-3","PreviousState":{"Code":80,"Name":"stopped"}},
{"InstanceId":"i-3","Tags":[{"Value":"hostname3","Key":"Name"}],"AmiLaunchIndex":0}
]
]
}
这是一个直接使用 INDEX
的方法。它假定调用以下形式,当然可能有不同的变化:
jq -n --argfile state state.json --argfile instance instance.json -f program.jq
其中 program.jq 包含:
INDEX($instance.Reservations[].Instances[]; .InstanceId)
| map_values(.Tags|from_entries.Name) as $dict
| $state
| .StoppingInstances |= map(. + {Hostname: $dict[.InstanceId]})
如果您不确定.InstanceId在instance.json中的位置,您可以修改上面的内容如下:
INDEX($instance | .. | objects | select(has("Instances")) | .Instances[];
.InstanceId)
| map_values(.Tags|from_entries.Name) as $dict
| $state
| .StoppingInstances |= map(. + {Hostname: $dict[.InstanceId]})