121

Let's say I have .env file contains lines like below:

USERNAME=ABC
PASSWORD=PASS

Unlike the normal ones have export prefix so I cannot source the file directly.

What's the easiest way to create a shell script that loads content from .env file and set them as environment variables?

3
  • How are values with spaces defined? Is it var="value with spaces", or var=value with spaces? The two call for quite different approaches. Commented Apr 6, 2017 at 23:58
  • 5
    Possible duplicate of Set environment variables from file Commented Sep 28, 2018 at 0:08
  • 2
    @NickGrealy, true, but there's an accepted answer that's badly wrong on that one (fails egregiously when values contain whitespace, and the stated workarounds are buggy) -- so if we were going to do duplicate linkage, I'd be going in the other direction. Commented Sep 24, 2022 at 15:49

11 Answers 11

224

If your lines are valid, trusted shell but for the export command

This requires appropriate shell quoting. It's thus appropriate if you would have a line like foo='bar baz', but not if that same line would be written foo=bar baz

set -a # automatically export all variables
source .env
set +a

If your lines are not valid shell

The below reads key/value pairs, and does not expect or honor shell quoting.

while IFS== read -r key value; do
  printf -v "$key" %s "$value" && export "$key"
done <.env
Sign up to request clarification or add additional context in comments.

13 Comments

source .env basically does the needful. just ensure that you do not have spaces in your .env values.
@AdépòjùOlúwáségun, without the set -a or the export, values are set only for the local shell, but not for its subprocesses. The OP explicitly says "environment variables", not "shell variables". foo=bar does not set an environment shell variable, it sets a shell variable.
@RodrigoTorres, that code has quite a lot of bugs; I wouldn't advise using it at all. echo $key and echo $value are themselves buggy -- see I just assigned a variable, but echo $variable shows something else!; if your value contains a * you could end up with a list of filenames. There are also considerably more efficient approaches available -- spinning up command substitutions and running external commands in them is expensive compared to stripping spaces with parameter expansion.
@j7skov, in the first section, it's the word after source (and was already present). In the second section, <.env goes after the done (and I've edited to add it there).
@digitalextremist, I'd consider [[ $key ]] || continue -- nice and self-contained, no need to keep chaining. ([[ suppresses globbing and string-splitting, so no need for the quotes within; and ! -z is equivalent to -n, and -n is the operation performed by a single argument test -- that latter bit is true not just for [[ but [ or test as well)
|
78

This will export everything in .env:

export $(xargs <.env)

Edit: this requires the environment values to not have whitespace. If this does not match your use case you can use the solution provided by Charles

Edit2: I recommend adding a function to your profile for this in any case so that you don't have to remember the details of set -a or how xargs works.

3 Comments

Consider if your .env was created with the following code: printf '%s\n' 'password="two words"' 'another=foo' >.env. In that case, the arguments passed to export would be password=two, words, and another=foo; words would no longer be part of the password, and would be a separate argument on its own (so the command would be trying to export a preexisting variable with the name words).
Would export $(xargs -L 1 <.env) solve that case @CharlesDuffy ?
I don't see how it could - the command substitution's output is still being word-split (and glob-expanded) before the final export command is assembled.
14

This script works perfectly for me (Jun 2023).

#!/bin/sh

# Load environment variables from .env file
[ ! -f .env ] || export $(grep -v '^#' .env | xargs)

Example of .env file:

# Database settings
DB_HOST=localhost
DB_PORT=5432
DB_NAME=mydatabase
DB_USER=myuser
DB_PASSWORD=mypassword

# API keys
API_KEY=abc123
SECRET_KEY=def456

# Other settings
DEBUG_MODE=true
LOG_LEVEL=info

1 Comment

But how to account for section names such as the following: [AWS] key= secret= The following is close but doesn't work: value=$(grep "^${section}[" .env | cut -d'[' -f2 | cut -d']' -f1 | grep "^${variable}=" | cut -d'=' -f2)
6

This is what I use:

load_dotenv(){
  # https://stackoverflow.com/a/66118031/134904
  # Note: you might need to replace "\s" with "[[:space:]]"
  source <("$1" | sed -e '/^#/d;/^\s*$/d' -e "s/'/'\\\''/g" -e "s/=\(.*\)/='\1'/g")
}

set -a
[ -f "test.env" ] && load_dotenv "test.env"
set +a

If you're using direnv, know that it already supports .env files out of the box :)

Add this to your .envrc:

[ -f "test.env" ] && dotenv "test.env"

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

1 Comment

cat $1 | ... misbehaves with filenames containing spaces or glob characters (cat -- "$1" | ... would be better, or just <"$1" ... to be both more correct and more efficient), and \s in a sed expression is a nonportable extension (it should be written [[:space:]] to be compatible with standard POSIX sed). Also, see wiki.bash-hackers.org/scripting/obsolete re: the function keyword; it's better just load_dotenv() { with no preceding function
2

Found this:

http://www.commandlinefu.com/commands/view/12020/export-key-value-pairs-list-as-environment-variables

while read line; do export $line; done < <(cat input)

UPDATE So I've got it working as below:

#!/bin/sh
while read line; do export $line; done < .env

5 Comments

< <(cat input) is a pretty complicated way to say < input, isn't it?
export "$line" is going to be a bit better-behaved, assuming it's one variable to a line but that the values are able to contain spaces.
That said, look at what this code does with line="hello world" -- you get the quotes exported as part of the literal data, rather than treated as syntax. That might be fine, but since the OP was saying the only reason they couldn't source the file was the lack of export prefixes, it very well might not.
Also, you'll want to add the argument -r to read so it doesn't mangle backslashes, and quote "$line" so its contents don't get string-split and glob-expanded before export sees them.
When you have it written as export $line instead of export "$line", a line like foo='bar=baz qux=meh' will write one variable foo with the value 'bar=baz, and a second variable qux with the value meh'. That's certainly not what the user wants/expects.
1

To complete the excellent accepted answer: https://stackoverflow.com/a/43267603/1169705

If your lines are not valid shell

Also catch for blank lines, other bash will complain.

while IFS== read -r key value; do
  if [[ ! -z "$key" ]]; then
    printf -v "$key" %s "$value" && export "$key"
  fi
done <.env

Comments

0

You can use an external command line tool which loads the environment variables from the desired .env.* file and runs the command of your choice directly, e.g. dotenvx or python-dotenv:

$ npm install @dotenvx/dotenvx --save
$ dotenvx run -f .env.example -- ./script.sh
$ pip install python-dotenv
$ dotenv -f .env.example run -- ./script.sh

Comments

0

I'm using the Windows machine to run the WSL. Here is what I do to set environment variables from .env file that is created by Windows and made that an alias in ~/.zshrc

# ~/.zshrc 
# Load set environment variables from .env file
load_env() {
   if [ -f .env ]; then
      dos2unix .env
      export $(grep -v '^#' .env | xargs)
      echo "Set environment variables from .env file"
   else
      echo ".env file not found in the current directory"
   fi
 }
 alias le='load_env'

You should install the dos2unix to converting file .env to Unix format:

sudo apt-get install dos2unix

Hope this will help!

Comments

0

I'm not exactly sure what circumstances are necessary for this to work (there are probably a handful of ways it can break), but the following very simple quick and dirty solution just did what I needed perfectly, so I'm really surprised to see that nobody has mentioned it yet:

env $(cat .env) sh

Given the following example .env file:

USER=name
PASS=word

This expands to env USER=name PASS=word sh, which makes the variables available for the executable.

References:


Edit: A nushell variation: env ...(cat .env | lines) nu

Comments

-1

use command below on ubuntu

$ export $(cat .env)

1 Comment

^^ This is how this should be done if the file contains a single var=value pair. And if the file only contains a value, this can be written as: export myvar=$(cat myfilepath)
-2

Try comand below

export `source .env`

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.