1

When I use Environment Variable to call aws cli in work terminal directly it will success:

AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx AWS_REGION=xxx aws elb describe-load-balancers --output json --debug

But if in shell, I first setup AWS_KEY_PAIR then execute the same command, it will returns to me AWS_ACCESS_KEY_ID=xxx: command not found My shell script looks like this:

function test(){
AWS_KEY_PAIR="AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY} AWS_SECRET_ACCESS_KEY=${AWS_SECRET_KEY} AWS_REGION=${AWS_REGION}"

${AWS_KEY_PAIR} aws elb describe-load-balancers --output json --debug }

Could anyone tell me why it success if I run first command directly in work terminal but fail in shell script? Is the AWS_KEY_PAIR can't be setup like this? Thank you very much!

suanziliu
  • 137
  • 10

1 Answers1

1

The problem lays in the way you modify the environment:

man bash : The environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments, as described above in PARAMETERS. These assignment statements affect only the environment seen by that command.

This means that if a variable exists, you can have it temporarily modified for a single command. Eg.

$ cat test.sh
#!/usr/bin/env zsh
echo $FOO
$ FOO="hello world"
$ echo $FOO
hello world
$ FOO="hello universe" ./test.sh
hello universe
$ echo $FOO
hello world

There you see that during the execution of FOO="hello universe" ./test.sh the variable FOO is temporarily modified. This is exactly what you do during execution of your command on the command line.

In your script however, you attempt something different. You assign the assignment of your script to a variable and then try to "execute this".

$ BAR="FOO=hello"
$ echo $BAR
FOO=hello
$ $BAR
bash: FOO=hello: command not found...

As you see, it tries to execute the command FOO=hello which is not a command but actually a string you try to execute. It is similar to typing $ "FOO=hello". So you can now imagine that

$ $BAR ./test.sh

will also not execute.

There is an evil workaround here using eval, but eval is evil.

man bash : eval [arg ...]

The args are read and concatenated together into a single command. This command is then read and executed by the shell, and its exit status is returned as the value of eval. If there are no args, or only null arguments, eval returns 0.

$ BAR="FOO=hello"
$ echo $BAR
FOO=hello
$ eval $BAR
$ echo $FOO
hello
$ FOO="hello world"
$ eval $BAR ./test.sh
hello

The latter examples are exactly what you try to attempt in your function test(). You assign your variable declaration to the variable AWS_KEY_PAIR and then execute aws with the modified environment ${AWS_KEY_PAIR}, but this will not work as AWS_KEY_PAIR is nothing more then a long string. You can thus fix it by placing eval in front of it, or by typing the full key pair out as

function test(){
AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY}           \
   AWS_SECRET_ACCESS_KEY=${AWS_SECRET_KEY}    \
   AWS_REGION=${AWS_REGION}                   \
   aws elb describe-load-balancers --output json --debug
}
kvantour
  • 25,269
  • 4
  • 47
  • 72