Pipes and text

How to set environment variables in bash and zsh

Learn how to set environment variables in Bash and zsh with export, how to persist them in .bashrc or .zshrc, and the env prefix trick for the Fish shell.

An environment variable is a name/value pair that a process passes down to the processes it starts. Your shell has them, and every program you launch from the shell inherits them.

Setting one works the same way in Bash and zsh. Assign the value and export it in one line:

export APP_ENV=development

Now read it back. Use printf, or look for it in the exported environment:

printf '%s\n' "$APP_ENV"
env | grep '^APP_ENV='

The first prints development. The second prints APP_ENV=development.

You’ll be tempted to check a variable by typing $APP_ENV on its own. Don’t. The shell replaces it with its value and then tries to run development as a command:

$APP_ENV
bash: development: command not found

Variable expansion gives you text, it does not print anything. That’s what echo and printf are for.

One value for one process

Often you don’t want to change your shell at all. You only need a variable for a single run. Put the assignment in front of the command:

APP_ENV=test node test.js

node sees APP_ENV=test. When it exits, your shell is unchanged, and printf '%s\n' "$APP_ENV" still says development. I use this all the time to run a test suite against a different database.

Fish handles this differently. There you prepend env:

env APP_ENV=test node test.js

Make it stick

An exported variable lives only in the current shell. Open a new terminal window and it’s gone.

To keep it around, add the export line to the startup file your shell reads. That’s ~/.zshrc for zsh and ~/.bashrc for interactive Bash. Then reload the file, or open a new shell:

source ~/.zshrc

If a variable you added does not show up, check which shell you’re running with echo "$SHELL". Editing .bashrc while your terminal runs zsh is a classic mistake. Login shells and interactive shells also read different files, so check your shell’s documentation instead of editing every dotfile you find.

Secrets

Environment variables are visible to the process, to its child processes, and to anyone who can run ps or read /proc on that machine. They are convenient, not encrypted storage. Don’t commit API keys to your startup files and don’t print them in logs.

Remove a variable

unset removes the variable from the current shell:

unset APP_ENV

Try the whole cycle yourself: export a value, read it from a child process with sh -c 'echo $APP_ENV', unset it, and run the same child again. The second time you get an empty line, because there is nothing left to inherit.

Lesson completed