-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
  • even if just for `bin/`: [do not parse `ls`](https://unix.stackexchange.com/questions/128985/why-not-parse-ls-and-what-to-do-instead), it's bound to run into a problem when names with spaces or newlines appear. What's the idea behind `ls bin | head -n1`? – Marcus Müller Jan 26 '22 at 15:24
  • plus, are you sure you want to put this into `$BASH_ENV`? It feels like something that's never useful for an interactive shell. – Marcus Müller Jan 26 '22 at 15:28
  • Use `"` instead of `'`. – ctx Jan 26 '22 at 15:40
  • I just need to store the result of AMI image to env variable and use it in the rest of my workflow. – OndrejK Jan 26 '22 at 16:12
  • "Does not work". What does it mean? You know you can't have a single-quoted string inside another single-quoted string, right? – Kusalananda Jan 26 '22 at 16:14

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.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
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
  • 133,243
  • 15
  • 236
  • 397