Reputation: 26193
I'm using WSL (Ubuntu 18.04) on Windows 10 and bash
.
I have a file filename.gpg
with the content:
export SOME_ENV_VAR='123'
Now I run the following commands:
$ $(gpg -d filename.gpg)
$ echo $SOME_ENV_VAR
'123' <-- with quotes
However, if I run it directly in the shell:
$ export SOME_ENV_VAR='123'
$ echo $SOME_ENV_VAR
123 < -- without quotes
Why does it behave like this? Why is there a difference between running a command using $()
and running it directly?
Aside: I got it working using eval $(gpg -d filename)
, I have no idea why this works.
Upvotes: 1
Views: 262
Reputation: 6144
Quotes in shell scripts do not behave differently from quotes in shell commands.
With the $(gpg -d filename.gpg)
syntax, you are not executing a shell script, but a regular single command.
gpg -d filename.gpg
From the following practical examples, you can see how it differs from executing a shell script:
SOME_ENV_VAR='123'
which is not understood as a variable assignment (you will get SOME_ENV_VAR='123': command not found
).export
).export SOME_ENV_VAR='123'
to export SOME_ENV_VAR=$PWD
, SOME_ENV_VAR will not contain the content of variable PWD, but the string $var
See how bash performs expansion when analyzing a command.
There are many steps. $(...)
is called "command substitution" and is the fourth step. When it is done, none of the previous steps will be performed again. This explains why your command does not work when you remove the export
word, and why variables are not substituted in the result.
Moreover "quote Removal" is the last step and the manual reads:
all unquoted occurrences of the characters ‘\’, ‘'’, and ‘"’ that did not result from one of the above expansions are removed
Since the single quotes resulted from the "command substitution" expansion, they were not removed. That's why the content of SOME_ENV_VAR is '123'
and not 123
.
eval
work?Because eval triggers another complete parsing of its parameters. The whole set of expansions is run again.
The arguments are concatenated together into a single command, which is then read and executed
Note that this means that you are still running one single command, and not a shell script. If your filename.gpg
script has several lines, subsequent lines will be added to the argument list of the first (and only) command.
Just use source
along with process substitution.
source <(gpg -d filename.gpg)
Contrary to eval
, source
is used to execute a shell script in the current context. Process substitution provides a pseudo-filename that contains the result of the substitution (i.e. the output of gpg
).
Upvotes: 4