Set environment variables from file of key/value pairs
BashVariablesEnvironment VariablesBash Problem Overview
TL;DR: How do I export a set of key/value pairs from a text file into the shell environment?
For the record, below is the original version of the question, with examples.
I'm writing a script in bash which parses files with 3 variables in a certain folder, this is one of them:
MINIENTREGA_FECHALIMITE="2011-03-31"
MINIENTREGA_FICHEROS="informe.txt programa.c"
MINIENTREGA_DESTINO="./destino/entrega-prac1"
This file is stored in ./conf/prac1
My script minientrega.sh
then parses the file using this code:
cat ./conf/$1 | while read line; do
export $line
done
But when I execute minientrega.sh prac1
in the command line it doesn't set the environment variables
I also tried using source ./conf/$1
but the same problem still applies
Maybe there is some other way to do this, I just need to use the environment variables of the file I pass as the argument of my script.
Bash Solutions
Solution 1 - Bash
This might be helpful:
export $(cat .env | xargs) && rails c
Reason why I use this is if I want to test .env
stuff in my rails console.
gabrielf came up with a good way to keep the variables local. This solves the potential problem when going from project to project.
env $(cat .env | xargs) rails
I've tested this with bash 3.2.51(1)-release
Update:
To ignore lines that start with #
, use this (thanks to Pete's comment):
export $(grep -v '^#' .env | xargs)
And if you want to unset
all of the variables defined in the file, use this:
unset $(grep -v '^#' .env | sed -E 's/(.*)=.*/\1/' | xargs)
Update:
To also handle values with spaces, use:
export $(grep -v '^#' .env | xargs -d '\n')
on GNU systems -- or:
export $(grep -v '^#' .env | xargs -0)
on BSD systems.
From this answer you can auto-detect the OS with this:
export-env.sh
#!/bin/sh
## Usage:
## . ./export-env.sh ; $COMMAND
## . ./export-env.sh ; echo ${MINIENTREGA_FECHALIMITE}
unamestr=$(uname)
if [ "$unamestr" = 'Linux' ]; then
export $(grep -v '^#' .env | xargs -d '\n')
elif [ "$unamestr" = 'FreeBSD' ]; then
export $(grep -v '^#' .env | xargs -0)
fi
Solution 2 - Bash
-o allexport
enables all following variable definitions to be exported. +o allexport
disables this feature.
set -o allexport
source conf-file
set +o allexport
Solution 3 - Bash
Problem with your approach is the export
in the while
loop is happening in a sub shell, and those variable will not be available in current shell (parent shell of while loop).
Add export
command in the file itself:
export MINIENTREGA_FECHALIMITE="2011-03-31"
export MINIENTREGA_FICHEROS="informe.txt programa.c"
export MINIENTREGA_DESTINO="./destino/entrega-prac1"
Then you need to source in the file in current shell using:
. ./conf/prac1
OR
source ./conf/prac1
Solution 4 - Bash
set -a
. ./env.txt
set +a
If env.txt
is like:
VAR1=1
VAR2=2
VAR3=3
...
Explanations -a is equivalent to allexport. In other words, every variable assignment in the shell is exported into the environment (to be used by multiple child processes). More information can be found in the Set builtin documentation:
> -a Each variable or function that is created or modified is given the export attribute and marked for export to the environment of subsequent commands. > > Using ‘+’ rather than ‘-’ causes these options to be turned off. The options can also be used upon invocation of the shell. The current set of options may be found in $-.
Solution 5 - Bash
I found the most efficient way is:
export $(xargs < .env)
Explanation
When we have a .env
file like this:
key=val
foo=bar
run xargs < .env
will get key=val foo=bar
so we will get an export key=val foo=bar
and it's exactly what we need!
Limitation
- It doesn't handle cases where the values have spaces in them. Commands such as env produce this format. – @Shardj
Solution 6 - Bash
The allexport
option is mentioned in a couple of other answers here, for which set -a
is the shortcut. Sourcing the .env really is better than looping over lines and exporting because it allows for comments, blank lines, and even environment variables generated by commands. My .bashrc includes the following:
# .env loading in the shell
dotenv () {
set -a
[ -f .env ] && . .env
set +a
}
# Run dotenv on login
dotenv
# Run dotenv on every new directory
cd () {
builtin cd $@
dotenv
}
Solution 7 - Bash
eval $(cat .env | sed 's/^/export /')
Solution 8 - Bash
The problem with source
is that it requires the file to have a proper bash syntax, and some special characters will ruin it: =
, "
, '
, <
, >
, and others. So in some cases you can just
source development.env
and it will work.
This version, however, withstands every special character in values:
set -a
source <(cat development.env | \
sed -e '/^#/d;/^\s*$/d' -e "s/'/'\\\''/g" -e "s/=\(.*\)/='\1'/g")
set +a
Explanation:
-a
means that every bash variable would become an environment variable/^#/d
removes comments (strings that start with#
)/^\s*$/d
removes empty strings, including whitespace"s/'/'\\\''/g"
replaces every single quote with'\''
, which is a trick sequence in bash to produce a quote :)"s/=\(.*\)/='\1'/g"
converts everya=b
intoa='b'
As a result, you are able to use special characters :)
To debug this code, replace source
with cat
and you'll see what this command produces.
Solution 9 - Bash
Here is another sed
solution, which does not run eval or require ruby:
source <(sed -E -n 's/[^#]+/export &/ p' ~/.env)
This adds export, keeping comments on lines starting with a comment.
.env contents
A=1
#B=2
sample run
$ sed -E -n 's/[^#]+/export &/ p' ~/.env
export A=1
#export B=2
I found this especially useful when constructing such a file for loading in a systemd unit file, with EnvironmentFile
.
Solution 10 - Bash
I have upvoted user4040650's answer because it's both simple, and it allows comments in the file (i.e. lines starting with #), which is highly desirable for me, as comments explaining the variables can be added. Just rewriting in the context of the original question.
If the script is callled as indicated: minientrega.sh prac1
, then minientrega.sh could have:
set -a # export all variables created next
source $1
set +a # stop exporting
# test that it works
echo "Ficheros: $MINIENTREGA_FICHEROS"
The following was extracted from the set documentation:
> This builtin is so complicated that it deserves its own section. set > allows you to change the values of shell options and set the > positional parameters, or to display the names and values of shell > variables. > > set [--abefhkmnptuvxBCEHPT] [-o option-name] [argument …] set > [+abefhkmnptuvxBCEHPT] [+o option-name] [argument …] > > If no options or arguments are supplied, set displays the names and values of all shell > variables and functions, sorted according to the current locale, in a > format that may be reused as input for setting or resetting the > currently-set variables. Read-only variables cannot be reset. In POSIX > mode, only shell variables are listed. > > When options are supplied, they set or unset shell attributes. > Options, if specified, have the following meanings: > > -a Each variable or function that is created or modified is given the export attribute and marked for export to the environment of > subsequent commands.
And this as well:
> Using ‘+’ rather than ‘-’ causes these options to be turned off. The > options can also be used upon invocation of the shell. The current set > of options may be found in $-.
Solution 11 - Bash
Not exactly sure why, or what I missed, but after running trough most of the answers and failing. I realized that with this .env file:
MY_VAR="hello there!"
MY_OTHER_VAR=123
I could simply do this:
source .env echo $MY_VAR
Outputs: Hello there!
Seems to work just fine in Ubuntu linux.
Solution 12 - Bash
Improving on Silas Paul's answer
exporting the variables on a subshell makes them local to the command.
(export $(cat .env | xargs) && rails c)
Solution 13 - Bash
SAVE=$(set +o | grep allexport) && set -o allexport && . .env; eval "$SAVE"
This will save/restore your original options, whatever they may be.
Using set -o allexport
has the advantage of properly skipping comments without a regex.
set +o
by itself outputs all your current options in a format that bash can later execute. Also handy: set -o
by itself, outputs all your current options in human-friendly format.
Solution 14 - Bash
The shortest way I found:
Your .env
file:
VARIABLE_NAME="A_VALUE"
Then just
. ./.env && echo ${VARIABLE_NAME}
Bonus: Because it's a short one-liner, it's very useful in package.json
file
"scripts": {
"echo:variable": ". ./.env && echo ${VARIABLE_NAME}"
}
Solution 15 - Bash
Here's my variant:
with_env() {
(set -a && . ./.env && "$@")
}
compared with the previous solutions:
- it does not leak variables outside scope (values from
.env
are not exposed to caller) - does not clobber
set
options - returns exit code of the executed command
- uses posix compatible
set -a
- uses
.
instead ofsource
to avoid bashism - command is not invoked if
.env
loading fails
with_env rails console
Solution 16 - Bash
If env
supports the -S
option one may use newlines or escape characters like \n
or \t
(see env):
env -S "$(cat .env)" command
.env
file example:
KEY="value with space\nnewline\ttab\tand
multiple
lines"
Test:
env -S "$(cat .env)" sh -c 'echo "$KEY"'
Solution 17 - Bash
Simpler:
- grab the content of the file
- remove any blank lines (just incase you separated some stuff)
- remove any comments (just incase you added some...)
- add
export
to all the lines eval
the whole thing
eval $(cat .env | sed -e /^$/d -e /^#/d -e 's/^/export /')
Another option (you don't have to run eval
(thanks to @Jaydeep)):
export $(cat .env | sed -e /^$/d -e /^#/d | xargs)
Lastly, if you want to make your life REALLY easy, add this to your ~/.bash_profile
:
function source_envfile() { export $(cat $1 | sed -e /^$/d -e /^#/d | xargs); }
(MAKE SURE YOU RELOAD YOUR BASH SETTINGS!!! source ~/.bash_profile
or.. just make a new tab/window and problem solved) you call it like this: source_envfile .env
Solution 18 - Bash
I work with docker-compose and .env
files on Mac, and wanted to import the .env
into my bash shell (for testing), and the "best" answer here was tripping up on the following variable:
.env
NODE_ARGS=--expose-gc --max_old_space_size=2048
Solution
So I ended up using eval
, and wrapping my env var defs in single quotes.
eval $(grep -v -e '^#' .env | xargs -I {} echo export \'{}\')
Bash Version
$ /bin/bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.
Solution 19 - Bash
You can use your original script to set the variables, but you need to call it the following way (with stand-alone dot):
. ./minientrega.sh
Also there might be an issue with cat | while read
approach. I would recommend to use the approach while read line; do .... done < $FILE
.
Here is a working example:
> cat test.conf
VARIABLE_TMP1=some_value
> cat run_test.sh
#/bin/bash
while read line; do export "$line";
done < test.conf
echo "done"
> . ./run_test.sh
done
> echo $VARIABLE_TMP1
some_value
Solution 20 - Bash
t=$(mktemp) && export -p > "$t" && set -a && . ./.env && set +a && . "$t" && rm "$t" && unset t
How it works
- Create temp file.
- Write all current environment variables values to the temp file.
- Enable exporting of all declared variables in the sources script to the environment.
- Read
.env
file. All variables will be exported into current environment. - Disable exporting of all declared variables in the sources script to the environment.
- Read the contents of the temp file. Every line would have
declare -x VAR="val"
that would export each of the variables into environment. - Remove temp file.
- Unset the variable holding temp file name.
Features
- Preserves values of the variables already set in the environment
.env
can have comments.env
can have empty lines.env
does not require special header or footer like in the other answers (set -a
andset +a
).env
does not require to haveexport
for every value- one-liner
Solution 21 - Bash
Building on other answers, here is a way to export only a subset of lines in a file, including values with spaces like PREFIX_ONE="a word"
:
set -a
. <(grep '^[ ]*PREFIX_' conf-file)
set +a
Solution 22 - Bash
Use shdotenv
dotenv support for shell and POSIX-compliant .env syntax specification
https://github.com/ko1nksm/shdotenv
eval "$(shdotenv)"
Usage
Usage: shdotenv [OPTION]... [--] [COMMAND [ARG]...]
-d, --dialect DIALECT Specify the .env dialect [default: posix]
(posix, ruby, node, python, php, go, rust, docker)
-s, --shell SHELL Output in the specified shell format [default: posix]
(posix, fish)
-e, --env ENV_PATH Location of the .env file [default: .env]
Multiple -e options are allowed
-o, --overload Overload predefined environment variables
-n, --noexport Do not export keys without export prefix
-g, --grep PATTERN Output only those that match the regexp pattern
-k, --keyonly Output only variable names
-q, --quiet Suppress all output
-v, --version Show the version and exit
-h, --help Show this message and exit
Requirements
shdotenv is a single file shell script with embedded awk script.
- POSIX shell (dash, bash, ksh, zsh, etc)
- awk (gawk, nawk, mawk, busybox awk)
Solution 23 - Bash
My .env:
#!/bin/bash
set -a # export all variables
#comments as usual, this is a bash script
USER=foo
PASS=bar
set +a #stop exporting variables
Invoking:
source .env; echo $USER; echo $PASS
Reference https://unix.stackexchange.com/questions/79068/how-to-export-variables-that-are-set-all-at-once
Solution 24 - Bash
My requirements were:
- simple .env file without
export
prefixes (for compatibility with dotenv) - supporting values in quotes: TEXT="alpha bravo charlie"
- supporting comments prefixed with # and empty lines
- universal for both mac/BSD and linux/GNU
Full working version compiled from the answers above:
set -o allexport
eval $(grep -v '^#' .env | sed 's/^/export /')
set +o allexport
Solution 25 - Bash
My version :
I print the file, remove commented lines, emptylines, and I split key/value from "=" sign. Then I just apply the export command.
The advantage of this solution is the file can contain special chars in values, like pipes, html tags, etc., and the value doesn't have to be surrounded by quotes, like a real properties file.
# Single line version
cat myenvfile.properties | grep -v '^#' | grep '=' | while read line; do IFS=\= read k v <<< $line; export $k="$v"; done
# Mutliline version:
cat myenvfile.properties | grep -v '^#' | grep '=' | while read line; do
IFS=\= read k v <<< $line
export $k="$v"
done
Solution 26 - Bash
I have issues with the earlier suggested solutions:
- @anubhava's solution makes writing bash friendly configuration files very annoying very fast, and also - you may not want to always export your configuration.
- @Silas Paul solution breaks when you have variables that have spaces or other characters that work well in quoted values, but
$()
makes a mess out of.
Here is my solution, which is still pretty terrible IMO - and doesn't solve the "export only to one child" problem addressed by Silas (though you can probably run it in a sub-shell to limit the scope):
source .conf-file
export $(cut -d= -f1 < .conf-file)
Solution 27 - Bash
I use this:
source <(cat .env \
| sed -E '/^\s*#.*/d' \
| tr '\n' '\000' \
| sed -z -E 's/^([^=]+)=(.*)/\1\x0\2/g' \
| xargs -0 -n2 bash -c 'printf "export %s=%q;\n" "${@}"' /dev/null)
First Removing comments:
sed -E '/^\s*#.*/d'
Then converting to null delimiters instead of newline:
tr '\n' '\000'
Then replacing equal with null:
sed -z -E 's/^([^=]+)=(.*)/\1\x0\2/g'
Then printing pairs to valid quoted bash exports (using bash printf for %q):
xargs -0 -n2 bash -c 'printf "export %s=%q;\n" "${@}"' /dev/null
Then finally sourcing all of that.
It should work for just about all cases with all special characters.
Solution 28 - Bash
First, create an environment file that will have all the key-value pair of the environments like below and named it whatever you like in my case its env_var.env
MINIENTREGA_FECHALIMITE="2011-03-31"
MINIENTREGA_FICHEROS="informe.txt programa.c"
MINIENTREGA_DESTINO="./destino/entrega-prac1"
Then create a script that will export all the environment variables for the python environment like below and name it like export_env.sh
#!/usr/bin/env bash
ENV_FILE="$1"
CMD=${@:2}
set -o allexport
source $ENV_FILE
set +o allexport
$CMD
This script will take the first argument as the environment file then export all the environment variable in that file and then run the command after that.
USAGE:
./export_env.sh env_var.env python app.py
Solution 29 - Bash
Here's my take on this. I had the following requirements:
- Ignore commented lines
- Allow spaces in the value
- Allow empty lines
- Ability to pass a custom env file while defaulting to .env
- Allow exporting as well as running commands inline
- Exit if env file doesn't exist
source_env() {
[ "$#" -eq 1 ] && env="$1" || env=".env"
[ -f "$env" ] || { echo "Env file $env doesn't exist"; return 1; }
eval $(grep -Ev '^#|^$' "$env" | sed -e 's/=\(.*\)/="\1/g' -e 's/$/"/g' -e 's/^/export /')
}
Usage after saving the function to your .bash_profile or equivalent:
source_env # load default .env file
source_env .env.dev # load custom .env file
(source_env && COMMAND) # run command without saving vars to environment
Inspired by Javier and some of the other comments.
Solution 30 - Bash
Modified from @Dan Kowalczyk
I put this in ~/.bashrc
.
set -a
. ./.env >/dev/null 2>&1
set +a
Cross-compatible very well with Oh-my-Zsh's dotenv plugin. (There is Oh-my-bash, but it doesn't have dotenv plugin.)
Solution 31 - Bash
White spaces in the value
There are many great answers here, but I found them all lacking support for white space in the value:
DATABASE_CLIENT_HOST=host db-name db-user 0.0.0.0/0 md5
I have found 2 solutions that work whith such values with support for empty lines and comments.
One based on sed and @javier-buzzi answer:
source <(sed -e /^$/d -e /^#/d -e 's/.*/declare -x "&"/g' .env)
And one with read line in a loop based on @john1024 answer
while read -r line; do declare -x "$line"; done < <(egrep -v "(^#|^\s|^$)" .env)
The key here is in using declare -x
and putting line in double quotes. I don't know why but when you reformat the loop code to multiple lines it won't work — I'm no bash programmer, I just gobbled together these, it's still magic to me :)
Solution 32 - Bash
How I save variables :
printenv | sed 's/\([a-zA-Z0-9_]*\)=\(.*\)/export \1="\2"/' > myvariables.sh
How I load them
source myvariables.sh
Solution 33 - Bash
I came across this thread when I was trying reuse Docker --env-file
s in a shell. Their format is not bash compatible but it is simple: name=value
, no quoting, no substitution. They also ignore blank lines and #
comments.
I couldn't quite get it posix compatible, but here's one that should work in bash-like shells (tested in zsh on OSX 10.12.5 and bash on Ubuntu 14.04):
while read -r l; do export "$(sed 's/=.*$//' <<<$l)"="$(sed -E 's/^[^=]+=//' <<<$l)"; done < <(grep -E -v '^\s*(#|$)' your-env-file)
It will not handle three cases in the example from the docs linked above:
bash: export: `123qwe=bar': not a valid identifier
bash: export: `org.spring.config=something': not a valid identifier
- and it will not handle the passthrough syntax (a bare
FOO
)
Solution 34 - Bash
try something like this
for line in `cat your_env_file`; do if [[ $line != \#* ]];then export $line; fi;done
Solution 35 - Bash
My .env file looks like:
DATABASE_URI="postgres://sa:***@localhost:5432/my_db"
VARIABLE_1="SOME_VALUE"
VALIABLE_2="123456788"
Using the @henke's ways, the exported value ends up containing the quotation marks "
"postgres://sa:***@localhost:5432/my_db"
"SOME_VALUE"
"123456788"
But I want the exported value to contain only:
postgres://sa:***@localhost:5432/my_db
SOME_VALUE
123456788
To fix it, I edit the command to delete the quotation marks:
export $(grep -v '^#' dev.env | tr --delete '"' | xargs -d '\n')
Solution 36 - Bash
sh -ac '. conf-file; yourcommand'
The -a
switch exports all variables, so that they are available to the program.
Unlike the longer version set -a; . conf-file; set +a; yourcommand
using sh
ensures the exported values are not permanently polluting the current environment. It sources and exports the variables just for the program run in a subshell.
Solution 37 - Bash
export
is the answer.
Interactive exercices
As [tag:shell] is interactive, you could try inline!
$ mkdir conf && printf 'MINIENTREGA_%s="%s"\n' FECHALIMITE 2011-03-31 FICHEROS
"informe.txt programa.c" DESTINO ./destino/entrega-prac1 >conf/prac1
$ set -- prac1
$ while read -r line; do export $line; done <"conf/$1"
bash: export: `programa.c"': not a valid identifier
$ while read -r line; do LANG=C export "$line"; done <"conf/$1" $ echo "$MINIENTREGA_FICHEROS" "informe.txt programa.c"
Note the double quotes!
source
alias .
$ set -- prac1 $ . "conf/$1" $ echo "$MINIENTREGA_FICHEROS" informe.txt programa.c
export
Ok, then now what's about export
command tell shell to export shell variables to environment... So you have to export script variables before use them is any subprocess (like ruby
, python
, perl
or even another shell
script.
Cleaning previous operations for further demos
$ declare +x MINIENTREGA_FECHALIMITE MINIENTREGA_FICHEROS MINIENTREGA_DESTINO
$ unset MINIENTREGA_FECHALIMITE MINIENTREGA_FICHEROS MINIENTREGA_DESTINO
So from an interactive shell, simpliest way to try this is to run another [tag:shell]:
$ set -- prac1
$ . "conf/$1"
$ bash -c 'declare -p MINIENTREGA_FICHEROS'
bash: line 1: declare: MINIENTREGA_FICHEROS: not found
$ export MINIENTREGA_FECHALIMITE MINIENTREGA_FICHEROS MINIENTREGA_DESTINO
$ bash -c 'declare -p MINIENTREGA_FICHEROS'
declare -x MINIENTREGA_FICHEROS="informe.txt programa.c"
Sample [tag:shell] wrapper for exporting variables
Minimal wrapper, without security concern (care when sourcing script editable by other users!!).
#!/bin/sh
while IFS== read -r varname _;do
case $varname in
*[!A-Za-z0-9_]* | '' ) ;;
* ) export $varname ;;
esac
done <conf/$1
. conf/$1
busybox sh -c 'set | grep MINIENTREGA'
Run with prac1
as argument, should produce:
MINIENTREGA_DESTINO='./destino/entrega-prac1' MINIENTREGA_FECHALIMITE='2011-03-31' MINIENTREGA_FICHEROS='informe.txt programa.c'
In fine
-
Sourcing your config file is same then declaring variables.
-
Exporting your variables is an instruct to shell to share his variables in global environment for any subprocess.
This two operation can be done in any order indifferently. The only requirement is that both operations are done before you try to run any subprocess.
You could even do both operation together, by exporting in your config file, for sample:
export MINIENTREGA_FECHALIMITE="2011-03-31"
export MINIENTREGA_FICHEROS="informe.txt programa.c"
export MINIENTREGA_DESTINO="./destino/entrega-prac1"
Solution 38 - Bash
If you're getting an error because one of your variables contains a value that contains white spaces you can try to reset bash's IFS
(Internal Field Separator) to \n
to let bash interpret cat .env
result as a list of parameters for the env
executable.
Example:
IFS=$'\n'; env $(cat .env) rails c
See also:
Solution 39 - Bash
This one copes with spaces on the RHS, and skips 'weird' vars such as bash module definitions (with '()' in them):
echo "# source this to set env vars" > $bld_dir/.env
env | while read line; do
lhs="${line%%=*}"
rhs="${line#*=}"
if [[ "$lhs" =~ ^[0-9A-Za-z_]+$ ]]; then
echo "export $lhs=\"$rhs\"" >> $bld_dir/.env
fi
done
Solution 40 - Bash
If you have an intention to have exec
as the last command of your script, you have an additional option by using execlineb
interpreter. This is how the last line of your script would look like:
#!/bin/sh
...
exec envfile -I /etc/default/bla envfile /etc/default/bla-bla my_cmd
envfile ...
are commands from execline
suite and they rely on "chain loading".
BTW, once you down this rabbit hole you may discover that you don't need shell anymore (... and reconsider your other life choices :-) It is quite useful for starting services with minimum overhead by using execlineb
interpreter instead of shell entirely, i.e.:
#!/bin/execlineb
...
envfile -I /etc/default/bla
envfile /etc/default/bla-bla
my_cmd
Solution 41 - Bash
My contribution to this is an expansion of the answer from @ user4040650 to allow for easy usage within a git repo. It will try to source the .env file from the current directory, or if that doesn't exist, the .env from the git repo you're in. It's helpful if you've cd'd into a child directory and then don't have to source ../../.env or whatnot.
I have this placed in my .bashrc, so I just need to call setenv
where needed
setenv() {
local env_path
if { [ -f .env ] && env_path='.env'; } || { env_path=$(git rev-parse --show-toplevel 2>/dev/null)/.env && [ -f "$env_path" ]; }; then
echo "sourcing $env_path"
set -o allexport
source "$env_path"
set +o allexport
else
echo "No env file found"
fi
}
Solution 42 - Bash
A POSIX-compliant solution (doesn't depend on bash)
As others have noted, the problem with using a for/while loop here, is that variables are not shared between a shell and its subshells. What we can do, however - is to pass text between shells using args/stdin/stdout.
Setting environment variables in a subshell is not going to help when we source the script
Variables are not going to propagate back up - but we know that we can send text back. And this text could also be code, which we can evaluate in the current shell using eval
.
What if we instead generate code for setting all the environment variables, and then eval the result?
create_exports_script() {
echo "$1" | while read line; do
echo "export $line"
done
}
file_contents=$(cat "./conf/myconf.env")
eval $(create_exports_script "$file_contents")
This kind of functional meta-programming in bash can be incredibly flexible. You can also generate other languages than bash/sh this way.
Solution 43 - Bash
I ended with a solution based on allexport
+ source
approach. The main idea here is to prevent override of existent variables.
function load_env_file() {
local FILE_PATH="${1}"
local EXISTENT_VARS=$(declare)
set -o allexport
source "${FILE_PATH}"
set +o allexport
# errors are supressed as "declare" returns also readonly vars which are not overridable
eval "${EXISTENT_VARS}" 2> /dev/null || true
}
# Usage example:
load_env_file "path/to/.env"
Solution 44 - Bash
For those who use ruby, I made a small utility gem called dotenv_export
.
usage
dotenv_export
is a small utility command which reads .env
file and converts it into export
statements using the ruby dotenv
implementation.
# first install `dotenv_export`
gem install dotenv_export
Then, in your .bash_profile
, or any shell environment in which you want to load the environment variables, execute following command:
eval "$(dotenv-export /path/to/.env)"