【问题标题】:jq: How to display a value only if its key exists?jq:如何仅在其键存在时才显示值?
【发布时间】:2020-08-24 12:53:57
【问题描述】:

我有以下 json:

{
    "SecurityGroups": [
        {
            "Description": "SG for ssh-proxy server",
            "GroupName": "ssh-proxy-SG",
            "IpPermissions": [
                {
                    "FromPort": 161,
                    "IpProtocol": "udp",
                    "IpRanges": [],
                    "Ipv6Ranges": [],
                    "PrefixListIds": [],
                    "ToPort": 161,
                    "UserIdGroupPairs": [
                        {
                            "GroupId": "sg-22e04e44",
                            "UserId": "XXXXXXXXXXXX"
                        }
                    ]
                },
                {
                    "FromPort": 22,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "Ipv6Ranges": [],
                    "PrefixListIds": [],
                    "ToPort": 22,
                    "UserIdGroupPairs": []
                },
                {
                    "FromPort": -1,
                    "IpProtocol": "icmp",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "Ipv6Ranges": [],
                    "PrefixListIds": [],
                    "ToPort": -1,
                    "UserIdGroupPairs": []
                }
            ],
            "OwnerId": "XXXXXXXXXXXX",
            "GroupId": "sg-4f1d8a35",
            "IpPermissionsEgress": [
                {
                    "IpProtocol": "-1",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "Ipv6Ranges": [],
                    "PrefixListIds": [],
                    "UserIdGroupPairs": []
                }
            ],
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "ssh-proxy-SG"
                }
            ],
            "VpcId": "vpc-d3131fbe"
        }
    ]
}

使用jq,我正在尝试显示这样一个列表:

161 tcp sg-22e04e44
22 tcp 0.0.0.0/0
-1 icmp 0.0.0.0/0

我只能打印端口和协议,但不能打印“.IpRanges[].CidrIp”,如下所示:

✗ aws ec2 describe-security-groups --group-id sg-4f1d8a35 --profile XXXX --region us-east-1 --output json | jq -r '.SecurityGroups[].IpPermissions[] | (.FromPort|tostring) + " " + .IpProtocol'
161 udp
22 tcp
-1 icmp

问题是有时(在本例中为 161 udp 规则)缺少“.IpRanges[].CidrIp”,这会导致错误。

我试过这个:

✗ aws ec2 describe-security-groups --group-id sg-4f1d8a35 --profile XXXXXXX --region us-east-1 --output json | jq -r '.SecurityGroups[].IpPermissions[] | (.FromPort|tostring) + " " + .IpProtocol + " " + .IpRanges[].CidrIp'

22 tcp 0.0.0.0/0
-1 icmp 0.0.0.0/0

但正如您所见,udp 行不见了。

也试过这个:

✗ aws ec2 describe-security-groups --group-id sg-4f1d8a35 --profile XXXXXXX --region us-east-1 --output json | jq -r '.SecurityGroups[].IpPermissions[] | .IpRanges[]? |= if has(.CidrIp) then (.FromPort|tostring) + " " + .IpProtocol + " " + .IpRanges[].CidrIp else (.FromPort|tostring) + " " + .IpProtocol + " " + .UserIdGroupPairs[].GroupId end'

{
  "FromPort": 161,
  "IpProtocol": "udp",
  "IpRanges": [],
  "Ipv6Ranges": [],
  "PrefixListIds": [],
  "ToPort": 161,
  "UserIdGroupPairs": [
    {
      "GroupId": "sg-22e04e44",
      "UserId": "XXXXXXX"
    }
  ]
}
jq: error (at <stdin>:72): Cannot iterate over null (null)

我做错了什么?

【问题讨论】:

  • 您是否注意到CidrIP 不存在于udp 记录中
  • 是的,忘了说,这正是我的问题
  • 你想要一个空字符串吗?你的输出应该是什么样子?
  • 161 tcp sg-22e04e44 22 tcp 0.0.0.0/0 -1 icmp 0.0.0.0/0
  • 啊,我以为 // 是一个注释,并没有将它包含在我的命令中,它工作得很好。很抱歉造成误会,您能回复一下吗?

标签: json key jq


【解决方案1】:

CidrIP 不存在于 udp 记录中。如果你想在.GroupIdCidrIp 之间交替,你可以像

.SecurityGroups[].IpPermissions[] |
.FromPort as $port          |
.IpProtocol as $prot        |
.IpRanges as $ip            |
.UserIdGroupPairs as $group |
[
  ($port|tostring),
  ($prot),
  (select($ip|length) | $ip[].CidrIp) //
  (select($group|length) | $group[].GroupId) //
  empty
] |
@tsv

产生你想要的输出

161 udp sg-22e04e44
22  tcp 0.0.0.0/0
-1  icmp    0.0.0.0/0

您可以将--raw-output/-r 模式与@csv@tsvjoin(" ") 中的任何一个一起使用,以表格形式表示输出。

jqplay - Online demo

【讨论】:

  • 这不是我想要做的,在 udp 规则中,如果“.IpRanges[]”不包含“.CidrIp”,我会尝试显示“.UserIdGroupPairs.GroupId” .
  • 查看编辑。显示的代码会产生准确的输出
  • 警告:可以直接使用has/1 测试密钥是否存在,但不能单独使用//。原因是如果 FOO 计算为单个值,比如 $foo,那么如果 $foo 为 false 或 null,FOO // BAR 计算为 BAR。
  • @peak: 希望现在更好
  • 嗯。 jq -n '([],{},0,null) | select(length)' 产生:[] {} 0 null
猜你喜欢
  • 2017-06-08
  • 1970-01-01
  • 2016-09-11
  • 1970-01-01
  • 1970-01-01
  • 2022-10-07
  • 1970-01-01
  • 2016-01-01
  • 2021-06-17
相关资源
最近更新 更多