'Is it possible to make the Bash "source" command keep environment variables passed in manually?
I have a file .env containing environment variables, e.g.:
TZ=UTC
NODE_ENV=development
Then, in my Bash scripts, I use:
set -o allexport; source .env; set +o allexport
This loads all the environment variables from .env.
However, if I manually pass environment variables to the script, they get overwritten by source. E.g. if I run NODE_ENV=production ./script.sh, I'd like it to keep NODE_ENV=production instead of using NODE_ENV=development from .env. How could I do this?
I'm using Ubuntu 20
Solution 1:[1]
Store environment "for later", source the file, then restore environment.
curenv=$(declare -p -x)
source .env
eval "$curenv"
Solution 2:[2]
You have to consider the following cases:
A variable X is already defined, and the sourced file should then not touch it.
A variable X is already defined, and the sourced file should then ensure that it is put into the environment.
A variable X is not yet defined, and the sourced file then should create it.
A variable X is not yet defined, and the sourced file then should create it and put it into the environment.
If you want 1+3, this is the simplest:
: ${X:=value}
The : is simply the bash no-op command and the := ensures that X gets the value if it is not defined yet. The export status (i.e. in environment or not in environment) is not affected.
If you want the combination 2+4, you could do either
export X=${X:-value}
or
: ${X:=value}
export X
The export statement ensures that the variable is in the environment afterwards, even if it was not in the environment before.
For my taste, the latter variant is more verbose, but clearer to read.
In theory you could also ask for the combination 1+3, i.e. not modify the environmental state of the variable, if it is defined already, but create it in the environment, if it is not defined. I can't think of a reasonable use case for this, but if you need, I can amend my answer and provide a solution for this as well.
Solution 3:[3]
You can't because the source command is invoked after passing external variables.
To accomplish that a workaround may require some coding:
- Don't use
sourcecommand. - Load
.envfile content and parse it into an associative array. - For each variable it contains, check if it is already assigned (externally).
- If it not assigned, assign the value into the array.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Alexis Wilke |
| Solution 3 |
