Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Load environment variables from dotenv / .env file in Bash
if [ ! -f .env ]
then
export $(cat .env | xargs)
fi
@tolmanam

This comment has been minimized.

Copy link

@tolmanam tolmanam commented Sep 14, 2018

FWIW - I found this helpful, but it didn't do what I had expected. Modified it slightly to result in the following.

if [ -f .env ]
then
  export $(cat .env | sed 's/#.*//g' | xargs)
fi
@rjchicago

This comment has been minimized.

Copy link

@rjchicago rjchicago commented Oct 2, 2018

The above worked fine for me, but thought I'd share the solution I went with:
https://stackoverflow.com/a/30969768/179329
set -o allexport; source .env; set +o allexport

@marcelovani

This comment has been minimized.

Copy link

@marcelovani marcelovani commented Apr 3, 2019

I like this

@hsundara

This comment has been minimized.

Copy link

@hsundara hsundara commented Aug 13, 2019

FWIW - I found this helpful, but it didn't do what I had expected. Modified it slightly to result in the following.

if [ -f .env ]
then
  export $(cat .env | sed 's/#.*//g' | xargs)
fi

You have won an award!

@alex-ross

This comment has been minimized.

Copy link

@alex-ross alex-ross commented Mar 24, 2020

I use this

envup() {
  local file=$([ -z "$1" ] && echo ".env" || echo ".env.$1")

  if [ -f $file ]; then
    set -a
    source $file
    set +a
  else
    echo "No $file file found" 1>&2
    return 1
  fi
}

It allows me to run envup to load the .env file or envup custom to load .env.custom.

@valmayaki

This comment has been minimized.

Copy link

@valmayaki valmayaki commented Apr 24, 2020

Here is a modified version of this code that allows for variable expansion

if [ -f .env ]; then
  export $(echo $(cat .env | sed 's/#.*//g'| xargs) | envsubst)
fi
@sebaxtian

This comment has been minimized.

Copy link

@sebaxtian sebaxtian commented May 5, 2020

Hi everyone, this works for me:

.env file

# Environment Variables
KAGGLE_USERNAME=sebaxtian
KAGGLE_KEY=example_kaggle_key
# Local .env
if [ -f .env ]; then
    # Load Environment Variables
    export $(cat .env | grep -v '#' | awk '/=/ {print $1}')
    # For instance, will be example_kaggle_key
    echo $KAGGLE_KEY
fi
@mortymacs

This comment has been minimized.

Copy link

@mortymacs mortymacs commented May 19, 2020

export $(grep -v '^#' .env | xargs)
@mortymacs

This comment has been minimized.

Copy link

@mortymacs mortymacs commented May 19, 2020

Thank you so much for the solution.

@mgrachev

This comment has been minimized.

Copy link

@mgrachev mgrachev commented Jul 7, 2020

In addition to using environment variables I can recommend the tool https://github.com/dotenv-linter/dotenv-linter  — it’s a lightning-fast linter for .env files. Written in Rust. Maybe it would be useful for you.

@binarymist

This comment has been minimized.

Copy link

@binarymist binarymist commented Jul 14, 2020

export $(grep -v '^#' .env | xargs)

Nice and simple, thanks @mortymacs

@alexanderchan

This comment has been minimized.

Copy link

@alexanderchan alexanderchan commented Aug 9, 2020

Slight variation if you have comments anywhere and aren't using the # for other purposes

export $(grep -v '#.*' .env | xargs)
@luni3359

This comment has been minimized.

Copy link

@luni3359 luni3359 commented Sep 10, 2020

Slight variation if you have comments anywhere and aren't using the # for other purposes

export $(grep -v '#.*' .env | xargs)

What's the difference? I take the one he shared omits lines that start with #, but I've no clue what yours do.

@luni3359

This comment has been minimized.

Copy link

@luni3359 luni3359 commented Sep 10, 2020

@valmayaki Thanks man, yours is the best. I really needed that variable substitution.

@j-fuentes

This comment has been minimized.

Copy link

@j-fuentes j-fuentes commented Sep 29, 2020

The above worked fine for me, but thought I'd share the solution I went with:
https://stackoverflow.com/a/30969768/179329
set -o allexport; source .env; set +o allexport

this is exactly what I wanted!

Thank you, @rjchicago.

@armikhael

This comment has been minimized.

Copy link

@armikhael armikhael commented Oct 30, 2020

Hi everyone, this works for me:

.env file

# Environment Variables
KAGGLE_USERNAME=sebaxtian
KAGGLE_KEY=example_kaggle_key
# Local .env
if [ -f .env ]; then
    # Load Environment Variables
    export $(cat .env | grep -v '#' | awk '/=/ {print $1}')
    # For instance, will be example_kaggle_key
    echo $KAGGLE_KEY
fi

If you wanted to use it like this " KAGGLE_KEY = example_kaggle_key". As would be the regular expression. (space Blanks)

Thank you

@lagden

This comment has been minimized.

Copy link

@lagden lagden commented Nov 30, 2020

well, I just import the file

.env

USER=foo
PWD=bar

some.sh

#!/bin/sh

. .env

echo $USER

exit 0
@PSchwalkowski

This comment has been minimized.

Copy link

@PSchwalkowski PSchwalkowski commented Dec 5, 2020

well, I just import the file

.env

USER=foo
PWD=bar

some.sh

#!/bin/sh

. .env

echo $USER

exit 0

This is working just fine for me. Thanks.

@froblesmartin

This comment has been minimized.

Copy link

@froblesmartin froblesmartin commented Dec 15, 2020

well, I just import the file

.env

USER=foo
PWD=bar

some.sh

#!/bin/sh

. .env

echo $USER

exit 0

This sets the defined variables in the file as shell variables (not environment variables) in the current shell session. If you run for example:
env | grep USER
This will return the USER environment variable set previously (if not by you, by the system). If the name of the variables in the file would be something different, that line would print nothing.

Something simple to do instead is just:
set -a; source .env; set +a

@contributorpw

This comment has been minimized.

Copy link

@contributorpw contributorpw commented Jan 8, 2021

.env

A=1
B=2

loadenv

#!/bin/bash
set -a; source .env; set +a

For me

$> source ./loadenv && node ./server
@IlanVivanco

This comment has been minimized.

Copy link

@IlanVivanco IlanVivanco commented Jan 20, 2021

The above worked fine for me, but thought I'd share the solution I went with:
https://stackoverflow.com/a/30969768/179329
set -o allexport; source .env; set +o allexport

Excellent tip!

@SlyDeath

This comment has been minimized.

Copy link

@SlyDeath SlyDeath commented Jan 23, 2021

loadenv

#!/bin/bash
set -a; source .env; set +a

Awesome!

@drjasonharrison

This comment has been minimized.

Copy link

@drjasonharrison drjasonharrison commented Jan 26, 2021

Slight variation if you have comments anywhere and aren't using the # for other purposes

export $(grep -v '#.*' .env | xargs)

What's the difference? I take the one he shared omits lines that start with #, but I've no clue what yours do.
grep -v "#" will omit any line with a hash anywhere on the line:

a=3 # this line will be omitted

While grep -v "^#" only omits lines that start with a #

# this line will be omitted
a=3 # this line will not be omitted
@kolypto

This comment has been minimized.

Copy link

@kolypto kolypto commented Feb 9, 2021

The Problem

The problem with .env files is that they're like bash, but not completely.
While in bash you'd sometimes put quotes around values:

name='value ! with > special & characters'

in .env files there are no special characters, and quotes are not supported: they're part of the value. As a result, such a string has to be escaped when imported into bash.

The Solution

This version 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 every a=b into a='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.

@drjasonharrison

This comment has been minimized.

Copy link

@drjasonharrison drjasonharrison commented Feb 11, 2021

@kolypto this doesn't work on comments after the assignment:
c=3 # three is prime

or with assignments to previously defined variables:
q='this string'
s=$q

@mverteuil

This comment has been minimized.

Copy link

@mverteuil mverteuil commented Feb 12, 2021

export $(echo $(cat .env | sed 's/#.*//g'| xargs) | envsubst)

This is the best one for me as I desperately needed POSIX variable substitution to work

@kolypto

This comment has been minimized.

Copy link

@kolypto kolypto commented Feb 13, 2021

@drjasonharrison the examples that you show are not a .env file; it's a bash file :)
If you want comments, and assigmnents, in the file that you're going to load, you don't need this thread at all ))) Just source it! bash can source bash )

@IlanVivanco

This comment has been minimized.

Copy link

@IlanVivanco IlanVivanco commented Feb 13, 2021

The cleanest solution I found for this was using allexport and source like this

set -o allexport
source .env set
+o allexport
@asheroto

This comment has been minimized.

Copy link

@asheroto asheroto commented Mar 28, 2021

For anyone researching in search engines (as that's how I came across this), here's my take on it, combining @kolypto addition of substitution + fixes, original poster's use of confirming the .env file exists, several mentioning the use of set -a

# Confirm .env file exists
if [ -f .env ]; then

    # Create tmp clone
    cat .env > .env.tmp;

    # Subtitutions + fixes to .env.tmp2
    cat .env.tmp | sed -e '/^#/d;/^\s*$/d' -e "s/'/'\\\''/g" -e "s/=\(.*\)/='\1'/g" > .env.tmp2

    # Set the vars
    set -a; source .env.tmp2; set +a

    # Remove tmp files
    rm .env.tmp .env.tmp2

fi

I'm favorable of cases with incorrect variable usage in .env
test=hi there

Using the above method will fix the issue automatically.

@ykshatroff

This comment has been minimized.

Copy link

@ykshatroff ykshatroff commented Mar 29, 2021

FWIW If you need to just run a command with environment from an env file, this could help:

env $(cat .env|xargs) CMD

provided there are no other lines except env definitions in form of VAR=VALUE. Don't remember where I found it, but does the trick for me.

@asheroto

This comment has been minimized.

Copy link

@asheroto asheroto commented Apr 1, 2021

FWIW If you need to just run a command with environment from an env file, this could help:

env $(cat .env|xargs) CMD

provided there are no other lines except env definitions in form of VAR=VALUE. Don't remember where I found it, but does the trick for me.

Well that could have saved me an hour or two. 😁 The main reason for my answer was to incorporate the fixes that @kolypto mentioned.

Thanks for the info.

@asolera

This comment has been minimized.

Copy link

@asolera asolera commented Apr 9, 2021

I had some problems with carriage return (\r) with dotenv files created via VS Code, so i'd like to share the code i used that resolved it:

export $(echo $(cat .env | sed 's/#.*//g' | sed 's/\r//g' | xargs) | envsubst)
@asheroto

This comment has been minimized.

Copy link

@asheroto asheroto commented Apr 9, 2021

I had some problems with carriage return (\r) with dotenv files created via VS Code, so i'd like to share the code i used that resolved it:

export $(echo $(cat .env | sed 's/#.*//g' | sed 's/\r//g' | xargs) | envsubst)

Thank you, great addition!

Since .env is so widely used, I think it would be a great addition to native Linux. Any clue how we could submit this as an addition to different distros? I mean integrated into the OS itself. I'm familiar with Linux and its commands but not how to submit an idea. I suppose it would be something I could fork and submit a pull request for.

@ko1nksm

This comment has been minimized.

Copy link

@ko1nksm ko1nksm commented Apr 12, 2021

Seeing that this thread has been going on for long years, I figured we need a dotenv tool for the shell.

And I wrote it.
https://github.com/ko1nksm/shdotenv

There is no formal specification for .env, and each is slightly different, but shdotenv supports them and correctly parses comments, whitespace, quotes, etc. It is a single file shell script that requires only awk and runs lightly.

There is no need to waste time on trial and error anymore.

@asheroto

This comment has been minimized.

Copy link

@asheroto asheroto commented Apr 13, 2021

Seeing that this thread has been going on for long years, I figured we need a dotenv tool for the shell.

And I wrote it.
https://github.com/ko1nksm/shdotenv

There is no formal specification for .env, and each is slightly different, but shdotenv supports them and correctly parses comments, whitespace, quotes, etc. It is a single file shell script that requires only awk and runs lightly.

There is no need to waste time on trial and error anymore.

This is great!

@mihow

This comment has been minimized.

Copy link
Owner Author

@mihow mihow commented Apr 13, 2021

Wow @ko1nksm! This looks incredibly thorough. I look forward to using it, thank you.

@GusGA

This comment has been minimized.

Copy link

@GusGA GusGA commented Apr 17, 2021

FWIW - I found this helpful, but it didn't do what I had expected. Modified it slightly to result in the following.

if [ -f .env ]
then
  export $(cat .env | sed 's/#.*//g' | xargs)
fi

👍 * 100

@lionelkouame

This comment has been minimized.

Copy link

@lionelkouame lionelkouame commented Apr 19, 2021

Thank you so much for your solution .

@muthugit

This comment has been minimized.

Copy link

@muthugit muthugit commented May 4, 2021

source .env

works for me

@abhidp

This comment has been minimized.

Copy link

@abhidp abhidp commented May 28, 2021

source .env

works for me

wont work if you have # in your .env

@muthugit

This comment has been minimized.

Copy link

@muthugit muthugit commented May 28, 2021

@abhidp sorry, i didn't check that case...

@Bioblaze

This comment has been minimized.

Copy link

@Bioblaze Bioblaze commented Jun 6, 2021

# Local .env
if [ -f .env ]; then
    # Load Environment Variables
    export $(cat .env | grep -v '#' | sed 's/\r$//' | awk '/=/ {print $1}' )
fi

is what I use.. <.< it allows me to comment inside of the .env file :X and handles /r proper.. hope that helps everyone <3

@Bashorun97

This comment has been minimized.

Copy link

@Bashorun97 Bashorun97 commented Jun 6, 2021

Here is a modified version of this code that allows for variable expansion

if [ -f .env ]; then
  export $(echo $(cat .env | sed 's/#.*//g'| xargs) | envsubst)
fi

This worked for me. Thanks

@quilicicf

This comment has been minimized.

Copy link

@quilicicf quilicicf commented Jul 1, 2021

Went for:

loadEnv() {
  local envFile="${1?Missing environment file}"
  local environmentAsArray variableDeclaration
  mapfile environmentAsArray < <(
    grep --invert-match '^#' "${envFile}" \
      | grep --invert-match '^\s*$'
  ) # Uses grep to remove commented and blank lines
  for variableDeclaration in "${environmentAsArray[@]}"; do
    export "${variableDeclaration//[$'\r\n']}" # The substitution removes the line breaks
  done
}

It does not glob or swallow quotes, tested with:

WITH_QUOTES=''

# Comment
WITNESS=whatever

WITH_GLOB=*.sh

In this folder (so the glob matches the shell file):

.
├── .env
└── loadEnvTest.sh

With command:

source ./loadEnvTest.sh; loadEnv .env; echo "$WITH_QUOTES $WITH_GLOB"

Outputs:

'' *.sh
@maxweber3

This comment has been minimized.

Copy link

@maxweber3 maxweber3 commented Jul 15, 2021

darbe habercisi

@msmans

This comment has been minimized.

Copy link

@msmans msmans commented Jul 31, 2021

One I use (bash specific) which behaves correctly in presence of calling environment override:

. <(sed -n 's/^\([^#][^=]*\)=\(.*\)$/\1=${\1:-\2}/p' .env 2>/dev/null) || true
@shlomi-viz

This comment has been minimized.

Copy link

@shlomi-viz shlomi-viz commented Aug 15, 2021

if [ ! -f .env ]
then
  export $(cat .env | xargs)
fi

I hate bash so much...... it took me 30 minutes to understand it should be if [ -f .env ] instead of if [ ! -f .env ] 😢

@chengxuncc

This comment has been minimized.

Copy link

@chengxuncc chengxuncc commented Aug 26, 2021

[ ! -f .env ] || export $(sed 's/#.*//g' .env | xargs)

Update:
TEXT="abc#def" not work as expected, so just replace line begin with #.

[ ! -f .env ] || export $(grep -v '^#' .env | xargs)
@ShivKJ

This comment has been minimized.

Copy link

@ShivKJ ShivKJ commented Aug 30, 2021

@chengxuncc

using export $(grep -v '^#' .env | xargs) could not export the following,

A=10
B=$A
C=${A}

now, echo $B produces $A while it should print 10

@chengxuncc

This comment has been minimized.

Copy link

@chengxuncc chengxuncc commented Aug 30, 2021

@chengxuncc

using export $(grep -v '^#' .env | xargs) could not export the following,

A=10
B=$A
C=${A}

now, echo $B produces $A while it should print 10

@ShivKJ Of course, it will equal to export A=10 B=$A C=${A} and doesn't work like shell script. Another example is /etc/environment have same behavior and don't accept variable definition.

@kolypto

This comment has been minimized.

Copy link

@kolypto kolypto commented Sep 12, 2021

If you're wondering how to load a .env file with direnv: direnv already supports that :)

dotenv "testing.env"

Docs: https://direnv.net/man/direnv-stdlib.1.html

@jhud

This comment has been minimized.

Copy link

@jhud jhud commented Sep 20, 2021

The Problem

The problem with .env files is that they're like bash, but not completely.
While in bash you'd sometimes put quotes around values:

name='value ! with > special & characters'

in .env files there are no special characters, and quotes are not supported: they're part of the value. As a result, such a string has to be escaped when imported into bash.

The Solution

This version 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 every a=b into a='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.

Thank you! I have some long and unusually formatted environment variables, and this was the only solution which didn't choke on them.

@jquick

This comment has been minimized.

Copy link

@jquick jquick commented Sep 21, 2021

~/bin/envs

set -a
source .env
set +a
exec $@

$> envs go run .

@lsotoj

This comment has been minimized.

Copy link

@lsotoj lsotoj commented Sep 21, 2021

export $(grep -v '^#' .env | xargs)

Thanks so much. I love it.

@aslamanver

This comment has been minimized.

Copy link

@aslamanver aslamanver commented Sep 24, 2021

export $(grep -v '^#' .env | xargs)

Hats off man

@xmarkclx

This comment has been minimized.

Copy link

@xmarkclx xmarkclx commented Oct 7, 2021

Doesn't work for me because of JWT in the .env with lots of newlines.
Had to manually vim copy paste the contents instead.

@nickbien

This comment has been minimized.

Copy link

@nickbien nickbien commented Oct 12, 2021

this worked for me, from @rjchicago snippet
set -o allexport; source .env; set +o allexport

@geekwhocodes

This comment has been minimized.

Copy link

@geekwhocodes geekwhocodes commented Oct 15, 2021

Here is a modified version of this code that allows for variable expansion

if [ -f .env ]; then
  export $(echo $(cat .env | sed 's/#.*//g'| xargs) | envsubst)
fi

worked like a charm. Thanks!

@NatoBoram

This comment has been minimized.

Copy link

@NatoBoram NatoBoram commented Oct 27, 2021

FWIW If you need to just run a command with environment from an env file, this could help:

env $(cat .env|xargs) CMD

provided there are no other lines except env definitions in form of VAR=VALUE. Don't remember where I found it, but does the trick for me.

You can actually get away without xargs

env $(cat .env) <command>
@fzancan-SpazioCodice

This comment has been minimized.

Copy link

@fzancan-SpazioCodice fzancan-SpazioCodice commented Oct 29, 2021

export $( grep -vE "^(#.*|\s*)$" .env )

@J5Dev

This comment has been minimized.

Copy link

@J5Dev J5Dev commented Nov 8, 2021

The cleanest solution I found for this was using allexport and source like this

set -o allexport
source .env set
+o allexport

This was by far the best solution here for me, removed all the complexity around certain chars, spaces comments etc. Just needed a tweak on formatting to prevent others being tripped up, should be:

set -o allexport
source .env
set +o allexport

@MrYutz

This comment has been minimized.

Copy link

@MrYutz MrYutz commented Nov 11, 2021

The above worked fine for me, but thought I'd share the solution I went with: https://stackoverflow.com/a/30969768/179329 set -o allexport; source .env; set +o allexport

I like this too.

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