Skip to content

Instantly share code, notes, and snippets.

Last active June 6, 2023 14:01
What would you like to do?
Load environment variables from dotenv / .env file in Bash
if [ ! -f .env ]
export $(cat .env | xargs)
Copy link

oh-my-zsh users can also activate the dotenv plugin.

Fantastic! Thanks @n1k0!

Copy link

spazm commented Mar 1, 2023

Posix compliant version built around set, [ ] and . Many thanks to the prior posters who brought up set -o a and set -a / set +a

This snippet will source a dotenv file, exporting the values into the environment. If allexport is already set, it leaves it set, otherwise it sets, reads, and unsets.

if [ -z "${-%%*a*}" ]; then
    set -a
    . ./.env
    set +a
    . ./.env

double brackets [[, source, setopt are not available in posix. Nor is the test [[ -o a ]] to check for set options. And we need to quote our comparison strings to deal with empty vars.

The code to check if an option is set is a bit of a pain. It could be a case statement or a grep on set -o like set -o | grep allexport | grep -q yes, but blech. Instead I've used parameter expansion with pattern matching to remove a maximum match from the $- variable containing a single line of the set options.

${-%%*a*} uses %% parameter expansion to remove the longest suffix matching the pattern *a*. If $- contains a then this expansion produces and empty string which we can test with -z or -n.

subtle bug if no options are set, so the comparison "$-" = "${-%%a*}" will check that the expansion changed the string. allexport is set if the two strings differ. And even % will work as we don't need a maximal match and can remove the leading * from our pattern match.

if [ "$-" = "${-%a*}" ]; then
    # allexport is not set
    set -a
    . ./.env
    set +a
    . ./.env

Copy link

When the values have newline chars \n, spaces or quotes, it can get messy.

After a lot of trial and error, I ended up with a variation of what @bergkvist proposed in (thank you very much!).

ENV_VARS="$(cat .env | awk '!/^\s*#/' | awk '!/^\s*$/')"

eval "$(
  printf '%s\n' "$ENV_VARS" | while IFS='' read -r line; do
    key=$(printf '%s\n' "$line"| sed 's/"/\\"/g' | cut -d '=' -f 1)
    value=$(printf '%s\n' "$line" | cut -d '=' -f 2- | sed 's/"/\\\"/g')
    printf '%s\n' "export $key=\"$value\""

Copy link

env $(cat .env)
this does not work for me but this one works

env $(cat .env|xargs) CMD

my .env has some special value such as FOO='VPTO&wH7$^3ZHZX$o$udY4&i'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment