Search code examples
bashjqaws-cli

Reading several variables from a single command's multi-line output


I'm running into an issue with the read command. I'm trying to get read to run through the output of my awscli command to extract VPC_ID, VPC_CIDR and VPC_NAME. Unfortunately its no longer working since upgrading to bash 5.0.

Here is the following code: read VPC_ID VPC_CIDR VPC_NAME <<<$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=${AWS_PROFILE}-vpc" --output json | jq -r '.Vpcs[] | .VpcId,.CidrBlock, (.Tags[]|select(.Key=="Name")|.Value)')

When I run aws ec2 describe-vpcs --filters "Name=tag:Name,Values=${AWS_PROFILE}-vpc" --output json | jq -r '.Vpcs[] | .VpcId,.CidrBlock, (.Tags[]|select(.Key=="Name")|.Value)'

I get my expected output but when I attached the read command in front of it, I'm only able to assign the first variable none of the other ones...


Solution

  • The problem is that read, by default, stops at the first newline it sees. (This can be overridden with the -d argument). You can work around this by running a separate read per variable, or running read with a different character used as the record delimiter.

    The first approach:

    { read -r VPC_ID && read -r VPC_CIDR && read -r VPC_NAME; } < <(
      aws ec2 describe-vpcs --filters "Name=tag:Name,Values=${AWS_PROFILE}-vpc" --output json \
      | jq -r '.Vpcs[] | .VpcId,.CidrBlock, (.Tags[]|select(.Key=="Name")|.Value)'
    )
    

    The second approach, which adds a printf '\0' when the inner command is successful, which read -d '' recognizes to mean the record is complete:

    IFS=$'\n' read -r -d '' VPC_ID VPC_CIDR VPC_NAME < <(
      aws ec2 describe-vpcs --filters "Name=tag:Name,Values=${AWS_PROFILE}-vpc" --output json \
      | jq -r '.Vpcs[] | .VpcId,.CidrBlock, (.Tags[]|select(.Key=="Name")|.Value)' \
      && printf '\0'
    )