I commonly need environment variables for personal or work projects. In many

cases, they are loaded automatically from a .env file: Docker/Podman can take

a --env-file .env flag and many programming languages have a dotenv library

that reads this file automatically. But when I want to run one-off commands in

the terminal, I need to parse this file manually.

When it is just one environment variable, I just export FOO=bar and call it a

day. But when there are more variables, I get lazy. Also, these export

commands get saved in my shell history file which is very handy and very scary:

to get a variable I exported in the past I just hit CTRL-R and start typing it

until I recover the full command. But I don’t want a command with a secret

saved in plain text in any shell history file (or any file at all).

Here’s a little trick to load all env vars from a .env file:

$ export $(<.env)This will read all lines of the .env file, and feed each word to the export

command.

For example, if you have this .env file:

CAT=Bob

OTHERCAT=DimitriThe $(<.env) magic will produce CAT=Bob OTHERCAT=Dimitri, which is then

passed to export. This exports all those variables.

But note: this trick is not a general-purpose .env parser, it only works for

simple KEY=VALUE lines. Spaces, quotes, special characters, and “comments”

kind of break this command. For example, this .env file:

CAT=Bob

OTHERCAT=Dimitri

# What about turtles?

TURTLE=SabrinaLeads to this:

export CAT=Bob OTHERCAT=Dimitri # What about turtles? TURTLE=Sabrina. Each

word is sent to export as an argument, which gives some errors:

$ export $(<.env)

-bash: export: `#': not a valid identifier

-bash: export: `turtles?': not a valid identifierBut we still get the TURTLE variable exported.

Another way to load a .env file in Bash is to enable the allexport option

and then source the file:

$ set -o allexport

$ source .env

$ set +o allexportDisabling allexport afterwards is good to keep our sanity: allexport

controls whether new or modified variables get automatically exported.

Turning it off restores the default state.

Another advantage of allexport + source is that it allows us to define

“dynamic” environment variables: we can use shell expansions and run commands

to, for example, query a secrets store. A .env file is now a shell script,

much more powerful than a mere data file:

CAT=Bob

OTHERCAT=Dimitri

# What about turtles?

TURTLE=Sabrina

LUCKY_NUMBER=${RANDOM}

API_KEY=$(keepassxc-cli show -sa Password ~/.secrets/personal.kdbx '/AWS/groot-key')The disadvantage of this more powerful file (i.e. a Bash script) is that it

breaks the export $(<.env) trick, and tools (e.g. docker run --env-file .env or a dotenv() function) that expect a simple KEY=VALUE file may

misbehave or crash completely. And because this executes the script, you

should only source files you trust.

PS: set -a is short for set -o allexport.