使用 JQ 精通 AWS CLI 输出过滤:高级技巧

使用jq配合AWS CLI JSON输出,过滤、重塑并导出云数据,用于脚本和报告。

掌握使用JQ进行AWS CLI输出过滤的高级技巧

当命令返回深度嵌套的JSON时,AWS CLI输出过滤会变得混乱。你可能只需要一个实例ID、一个标签值或一份简短的CSV报告,但像aws ec2 describe-instances这样的命令返回的数据远多于这些。

AWS CLI内置了使用JMESPath的--query选项,对于简单查询来说通常是合适的工具。当你需要更丰富的JSON重塑、条件逻辑、CSV输出或可在shell脚本中重用的过滤器时,jq就派上用场了。

从JSON输出开始

jq读取JSON,因此要让AWS CLI明确返回JSON:

aws ec2 describe-instances --output json

你也可以使用aws configure将JSON设置为默认输出格式,但在示例和脚本中使用--output json能清晰地表明依赖关系。

如果系统尚未安装jq,请使用系统包管理器进行安装:

sudo apt update && sudo apt install jq
sudo dnf install jq
brew install jq

读取和检查AWS JSON

恒等过滤器.会返回输入的JSON。当你想在学习响应结构时获得美化打印的输出,这会很方便:

aws ec2 describe-instances --output json | jq '.'

要选择顶级键,请使用点号表示法:

aws ec2 describe-instances --output json | jq '.Reservations'

大多数AWS命令将有用数据包装在数组中。对于EC2实例,结构是Reservations[]后跟Instances[],因此通常需要两个层级。

遍历数组

使用.[]从数组中输出每个元素。此命令打印所有预留中的每个EC2实例ID:

aws ec2 describe-instances --output json | jq '.Reservations[].Instances[].InstanceId'

默认情况下,字符串输出包含JSON引号。当需要用于shell循环或其他命令的原始文本时,请添加-r

aws ec2 describe-instances --output json | jq -r '.Reservations[].Instances[].InstanceId'

你也可以构建一个只包含所需字段的较小对象:

aws ec2 describe-instances --output json |
  jq '.Reservations[].Instances[] | {id: .InstanceId, state: .State.Name, type: .InstanceType}'

这将生成紧凑的JSON记录,而不是完整的EC2响应。

使用select()进行过滤

当你只想要符合某个条件的记录时,请使用select()。此示例列出正在运行的实例ID:

aws ec2 describe-instances --output json |
  jq -r '.Reservations[].Instances[] | select(.State.Name == "running") | .InstanceId'

jq过滤器中的字符串字面量使用双引号,例如"running"。如果你将整个jq程序用单引号括起来,你的shell会安全地传递这些双引号。

要进行更具体的检查,请按实例类型过滤:

aws ec2 describe-instances --output json |
  jq -r '.Reservations[].Instances[] | select(.InstanceType == "t3.micro") | .InstanceId'

安全处理可选字段

AWS资源通常会省略字段。标签是一个常见的例子。如果实例没有Tags数组,.Tags[]可能会失败。请使用可选迭代器.Tags[]?

aws ec2 describe-instances --output json |
  jq '.Reservations[].Instances[] | {id: .InstanceId, name: (.Tags[]? | select(.Key == "Name") | .Value)}'

这可以工作,但当标签缺失时可能不会产生name值。对于脚本,默认值通常更容易处理:

aws ec2 describe-instances --output json |
  jq '.Reservations[].Instances[] | {
    id: .InstanceId,
    name: ((.Tags[]? | select(.Key == "Name") | .Value) // "unnamed")
  }'

返回数组而非流

许多jq过滤器会输出一个值流。如果另一个工具期望一个有效的JSON数组,请将表达式用方括号括起来:

aws ec2 describe-instances --output json |
  jq '[.Reservations[].Instances[].InstanceId]'

这在为另一个自动化步骤编写JSON文件时非常有用。

导出CSV或TSV

对于适合电子表格的报告,构建一个字段数组并将其传递给@csv@tsv。使用-r以便jq写入原始CSV行而不是JSON字符串:

aws ec2 describe-instances --output json |
  jq -r '.Reservations[].Instances[] | [.InstanceId, .InstanceType, .State.Name] | @csv'

要包含标题行,请在数据行之前输出它:

aws ec2 describe-instances --output json |
  jq -r '["instance_id","instance_type","state"], (.Reservations[].Instances[] | [.InstanceId, .InstanceType, .State.Name]) | @csv'

实际示例:查找未关联的弹性IP

未关联的弹性IP地址可能会产生可避免的成本。此命令列出AWS未返回AssociationId的公共IP:

aws ec2 describe-addresses --output json |
  jq -r '.Addresses[] | select(.AssociationId == null) | .PublicIp'

如果打印出地址,请在释放前检查它们:

aws ec2 release-address --allocation-id eipalloc-0123456789abcdef0

在检查结果之前,不要直接将释放命令从发现查询中通过管道传递。短暂的检查步骤比从删除错误资源中恢复更便宜。

何时使用--query替代

对于简单的投影,使用AWS CLI --query,因为它在输出格式化之前运行,并使命令保持自包含:

aws ec2 describe-instances \
  --query 'Reservations[].Instances[].InstanceId' \
  --output text

当结果需要更多转换时,例如回退值、CSV格式化、组合字段或使用jq语法更易读的长过滤器,请使用jq。

要点

使用--output json作为AWS CLI和jq之间的交接点。然后结合.[]select()、对象构造、//默认值和-r原始输出,将大型AWS响应转换为脚本或报告所需的确切数据。