-1

I'm trying to store ENV variable using CircleCi boxes. I usually do it like this:

echo 'export FILE=$(ls bin | head -n 1)' >> $BASH_ENV

That works perfectly for simple commands and it will produce output in $BASH_ENV

export FILE=$(ls bin | head -n 1)

Now for extended commands where I need to just run it once, this is complicated and it doesn't work.

echo 'export INSTANCE_ID=$(aws ec2 run-instances --instance-type t3.large\
--image-id $AMI --key-name circleci-key --count 1 --security-group-ids $SG\
--subnet-id $SUBNET --network-interfaces "{\"AssociatePublicIpAddress\": true, \"DeviceIndex\": 0, \"SubnetId\": \"$SUBNET\", \"Groups\": [\"$SG\"]}"\
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=instance-from-circleci}]'\
 | jq '.Instances[0].InstanceId' --raw-output)' >> $BASH_ENV

This code once added to $BASH_ENV is executed everytime I run source $BASH_ENV.

Is there a way to simply store this value once to a variable and then add it to the echo line already in its final form?

Something like:

echo 'export $INSTANCE_ID' >> $BASH_ENV

2 Answers2

2

To avoid the headaches with escaping quotes, it's easier to use a here-document:

cat << 'EOF' >> "$BASH_ENV"
export INSTANCE_ID="$(
  aws ec2 run-instances \
    --instance-type t3.large \
    --image-id "$AMI" \
    --key-name circleci-key \
    --count 1 \
    --security-group-ids "$SG" \
    --subnet-id "$SUBNET" \
    --network-interfaces '
      {
        "AssociatePublicIpAddress": true,
        "DeviceIndex": 0,
        "SubnetId": "'"$SUBNET"'",
        "Groups": ["'"$SG"'"]
      }' \
    --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=instance-from-circleci}]' |
  jq '.Instances[0].InstanceId' --raw-output)"
EOF

(also fixing your problems with missing quotes, and improving legibility).

Note the quotes around EOF ('EOF') are important. Without them, the variables and command substitutions within the here-documents would be expanded and the trailing \ treated as line continuation at the time the here-document is generated.

1

Now for extended commands where I need to just run it once, [...] Is there a way to simply store this value once to a variable and then add it to the echo line already in its final form?

Well, basically, instead of printing the var=$(command...) part to $BASH_ENV, run the command substitution in the script itself, and print the result. So:

var=$(some command)
echo "var='$var'" >> file

But note that the var='value' will go through the shell's quote processing etc. so if the value can contain single quotes, that will break.

Instead, you can use e.g. printf %q in Bash:

var=$(some command)
printf "var=%q\n" "$var" >> file

If the value in $var was e.g. it ain't so, that would produce var=var=it\ ain\'t\ so. Ugly, but produces the same value when executed.

ilkkachu
  • 138,973