【问题标题】:jq output is empty when tag name does not exist标签名不存在时jq输出为空
【发布时间】:2021-12-15 19:07:21
【问题描述】:

当我运行 jq 命令从 amazon cli 解析 json 文档时,我遇到了以下问题。

我正在解析 IP 地址和一个名为“环境”的标签。实例中的环境标签不存在,因此它不会给我任何结果。

以下是 AWS CLI 返回的相关输出示例

{
  "Reservations": [
    {
      "Instances": [
        {
          "PrivateIpAddress": "10.0.0.1",
          "Tags": [
            {
              "Key": "Name",
              "Value": "Balance-OTA-SS_a"
            },
            {
              "Key": "Environment",
              "Value": "alpha"
            }
          ]
        }
      ]
    },
    {
      "Instances": [
        {
          "PrivateIpAddress": "10.0.0.2",
          "Tags": [
            {
              "Key": "Name",
              "Value": "Balance-OTA-SS_a"
            }
          ]
        }
      ]
    }
  ]
}

我正在运行以下命令

aws ec2 describe-instances --filters "Name=tag:Name,Values=Balance-OTA-SS_a" | jq -c '.Reservations[].Instances[] | ({IP: .PrivateIpAddress, Ambiente: (.Tags[]|select(.Key=="Environment")|.Value)})'

## output
empty

即使环境标签不存在,如何在命令输出中显示 IP 地址?

问候,

【问题讨论】:

  • 请查看minimal reproducible example 指南。具体来说,如果没有匹配的标签,你想要什么结果?您希望出现“Ambiente”键吗?
  • 我的英语不好,我重新提出了我的问题。
  • 恕我直言,一个更好的例子是显示示例 JSON 数据,这样就不必获取 aws ec2 数据来回答 JQ 问题。
  • 我的答案中包含了示例输入,但是请在根据 AWS 命令​​的输出询问 jq 问题时包含示例输入,即使其他人获取这样的测试数据也非常不方便确实有一个 AWS 账户,而许多本来可以回答问题的人却没有。

标签: json amazon-web-services jq


【解决方案1】:

让我们假设这个输入:

{
  "Reservations": [
    {
      "Instances": [
        {
          "PrivateIpAddress": "10.0.0.1",
          "Tags": [
            {
              "Key": "Name",
              "Value": "Balance-OTA-SS_a"
            },
            {
              "Key": "Environment",
              "Value": "alpha"
            }
          ]
        }
      ]
    },
    {
      "Instances": [
        {
          "PrivateIpAddress": "10.0.0.2",
          "Tags": [
            {
              "Key": "Name",
              "Value": "Balance-OTA-SS_a"
            }
          ]
        }
      ]
    }
  ]
}

这是 describe-instances 返回的格式,但删除了所有不相关的字段。

请注意,标签始终是一个对象列表,每个对象都有一个Key 和一个Value。这种格式对于from_entries 来说是完美,它可以将这个标签列表转换成一个方便的映射对象。试试这个:

.Reservations[].Instances[] |
{
  IP: .PrivateIpAddress,
  Ambiente: (.Tags|from_entries.Environment)
}
{"IP":"10.0.0.1","Ambiente":"alpha"}
{"IP":"10.0.0.2","Ambiente":null}

这回答了如何去做。但您可能想了解为什么您的方法不起作用。

.Reservations[].Instances[] |
{
  IP: .PrivateIpAddress,
  Ambiente: (.Tags[]|select(.Key=="Environment")|.Value)
}

您在标签上使用的.[] 过滤器可以返回零个或多个结果。同样,select 过滤器可以消除部分或全部项目。当您将这个inside 应用到对象构造函数(从{} 的表达式)时,您会导致整个对象被创建的次数不定。您需要非常小心使用这些过滤器的位置,因为这通常不是您想要的。您通常希望执行以下操作之一:

  • 将返回多个结果的表达式包装在数组构造函数[ ... ] 中。这样,您就可以输出一次包含可能具有零个或多个项目的数组的父对象,而不是输出可能零次或多次的父对象。例如。
    [.Tags[]|select(.Key=="Environment")]
    
  • map 应用于数组以使其保持为数组但处理其内容,例如
    .Tags|map(select(.Key=="Environment"))
    
  • 应用first(expr) 仅捕获表达式发出的第一个值。如果表达式可能发出零个项目,您可以使用逗号运算符提供默认值,例如
    first((.Tags[]|select(.Key=="Environment")),null)
    
  • 应用一些其他数组级函数,例如from_entries
    .Tags|from_entries.Environment
    

【讨论】:

    【解决方案2】:

    您可以使用if ... then ... else ... end 构造或//。例如:

    .Reservations[].Instances[]
    | {IP: .PrivateIpAddress} + 
      ({Ambiente: (.Tags[]|select(.Key=="Environment")|.Value)}
       // null)
    

    【讨论】:

    • 如果标签不存在,我至少需要显示IP地址,这样输出仍然是空的。
    猜你喜欢
    • 2014-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多