如何通过单次jq调用提取并分组AWS EC2实例的私有IP?
如何用单次jq调用完成EC2实例名与对应私有IP的分组整理?
我有两台EC2实例,每台各拥有3个私有IP。目前我通过多次jq调用成功提取并整理出JSON格式的实例名与对应IP列表:
首先执行命令:
aws ec2 describe-instances | jq '.Reservations[] | .Instances[] | (.Tags | { "iname": ( map ( select(.Value | contains("my-vm")))[] | .Value ) } ) + ( { "ip": ( .NetworkInterfaces[].PrivateIpAddress) } )' | jq -s .
得到结果:
[ { "iname": "my-vm-b", "ip": "10.11.2.145" }, { "iname": "my-vm-b", "ip": "10.11.1.146" }, { "iname": "my-vm-b", "ip": "10.11.10.144" }, { "iname": "my-vm-a", "ip": "10.11.1.9" }, { "iname": "my-vm-a", "ip": "10.11.10.125" }, { "iname": "my-vm-a", "ip": "10.11.2.85" } ]
接着追加命令:
... | jq ' group_by(.iname)[] | {(.[] | .iname): [.[] | .ip]}' | jq -s .
最终得到期望的分组结果:
[ { "my-vm-a": [ "10.11.1.9", "10.11.10.125", "10.11.2.85" ] }, { "my-vm-b": [ "10.11.2.145", "10.11.1.146", "10.11.10.144" ] } ]
我总共调用了4次jq,认为操作存在冗余,想咨询是否可以通过单次jq调用完成上述全部操作?
当然可以!单次jq调用就能搞定
你可以把所有逻辑合并到一个jq表达式里,完全避免多次调用的冗余。这里是合并后的完整命令:
aws ec2 describe-instances | jq ' .Reservations[] | .Instances[] | ( .Tags | map(select(.Value | contains("my-vm")))[0].Value ) as $iname | .NetworkInterfaces[].PrivateIpAddress as $ip | {iname: $iname, ip: $ip} | group_by(.iname)[] | { (.[0].iname): [.[] | .ip] } | [.] '
分步解释这个表达式:
- 遍历EC2实例数据:
.Reservations[] | .Instances[]先展开所有预约和实例,拿到单个实例对象。 - 提取实例名:
( .Tags | map(select(.Value | contains("my-vm")))[0].Value ) as $iname筛选出包含"my-vm"的标签值,存为变量$iname(这里默认每个实例只有一个符合条件的标签,和你原来的逻辑一致)。 - 提取私有IP:
.NetworkInterfaces[].PrivateIpAddress as $ip展开每个实例的所有私有IP,存为变量$ip。 - 构造基础键值对:
{iname: $iname, ip: $ip}生成和你第一次jq调用一样的单个实例-IP对象。 - 分组并整理结构:
group_by(.iname)[] | { (.[0].iname): [.[] | .ip] }按实例名分组,然后把每组转换成{实例名: [IP列表]}的结构。 - 包裹为数组:
[.]把每个分组对象放到数组里,得到你最终想要的结果格式。
更高效的reduce版本
还可以用reduce直接构建目标结构,跳过先生成中间数组再分组的步骤,执行效率更高:
aws ec2 describe-instances | jq ' reduce (.Reservations[] | .Instances[]) as $inst ({}; ($inst.Tags | map(select(.Value | contains("my-vm")))[0].Value) as $iname | .[$iname] += $inst.NetworkInterfaces[].PrivateIpAddress ) | to_entries | map({(.key): .value}) '
这个版本的逻辑:
- 初始化一个空对象
{}作为累加器。 - 遍历每个实例,提取实例名
$iname。 - 把当前实例的所有私有IP直接追加到累加器中对应
$iname的数组里。 - 最后用
to_entries把对象转换成键值对数组,再映射成你需要的{实例名: IP列表}格式的数组。
内容的提问来源于stack exchange,提问作者chicofranchico
相关产品推荐
相关产品推荐

