Extracting Multiple EC2 Instance Attributes with jq: Combining PublicDnsName and VpcId in AWS CLI Output


4 views

When working with AWS EC2 instances through the CLI, we often need to extract specific attributes in combination. The standard aws ec2 describe-instances command returns a complex JSON structure where instance details are nested within Reservations and Instances arrays.

The simplest approach extracts one field at a time:

aws ec2 describe-instances | jq '.Reservations[].Instances[].PublicDnsName'
aws ec2 describe-instances | jq '.Reservations[].Instances[].VpcId'

To output both PublicDnsName and VpcId together for each instance:

aws ec2 describe-instances | jq -r '.Reservations[].Instances[] | "\(.PublicDnsName) \(.VpcId)"'

This uses jq's string interpolation to format the output with a space separator. You can customize the separator:

# With comma separator
aws ec2 describe-instances | jq -r '.Reservations[].Instances[] | "\(.PublicDnsName),\(.VpcId)"'

# With tab separator
aws ec2 describe-instances | jq -r '.Reservations[].Instances[] | [.PublicDnsName, .VpcId] | @tsv'

To specifically identify Classic instances (those without VPC):

aws ec2 describe-instances | jq -r '.Reservations[].Instances[] | select(.VpcId == null) | .PublicDnsName'

For more complex output with headers and multiple fields:

aws ec2 describe-instances | jq -r '
  ["DNS_NAME", "VPC_ID", "INSTANCE_ID"] | @tsv,
  (.Reservations[].Instances[] | 
   [.PublicDnsName, .VpcId, .InstanceId] | @tsv)'

Create a CSV for further processing:

aws ec2 describe-instances | jq -r '
  "DNS_NAME,VPC_ID,INSTANCE_TYPE",
  (.Reservations[].Instances[] | 
   [.PublicDnsName, .VpcId, .InstanceType] | @csv)' > instances.csv

When working with AWS EC2 instances through the CLI, the JSON output can be complex. A typical describe-instances output contains nested structures with Reservations and Instances arrays. While extracting single fields is straightforward, combining multiple fields requires more advanced jq techniques.

The simplest case extracts just one field:

aws ec2 describe-instances | jq '.Reservations[].Instances[].PublicDnsName'

To get both PublicDnsName and VpcId in a single output, we can use object construction in jq:

aws ec2 describe-instances | jq '.Reservations[].Instances[] | {PublicDnsName, VpcId}'

For tabular output with custom separators:

aws ec2 describe-instances | jq -r '.Reservations[].Instances[] | "\(.PublicDnsName),\(.VpcId)"'

To specifically identify Classic instances (where VpcId is null/undefined):

aws ec2 describe-instances | jq -r '.Reservations[].Instances[] | select(.VpcId == null or .VpcId == "null" or .VpcId == "") | "\(.InstanceId),\(.PublicDnsName)"'

Combine multiple filters for practical use cases:

# Find running Classic instances
aws ec2 describe-instances --filters Name=instance-state-name,Values=running | 
jq -r '.Reservations[].Instances[] | select(.VpcId == null) | "\(.InstanceId) \(.PublicDnsName)"'

Format output as CSV with headers:

aws ec2 describe-instances | 
jq -r '["InstanceId","PublicDnsName","VpcId"], (.Reservations[].Instances[] | [.InstanceId, .PublicDnsName, .VpcId]) | @csv'

Some instances might not have PublicDnsName. Use the // operator for defaults:

aws ec2 describe-instances | 
jq -r '.Reservations[].Instances[] | "\(.InstanceId),\(.PublicDnsName // "N/A"),\(.VpcId // "CLASSIC")"'

For large datasets, add --no-cli-pager and --output json to AWS CLI for better performance:

aws ec2 describe-instances --no-cli-pager --output json | 
jq -r '.Reservations[].Instances[] | select(.VpcId == null) | .InstanceId'