How to Use Environment Variables in Bash

How to Use Environment Variables in Bash

How to Use Environment Variables in Bash

I remember the moment environment variables finally clicked for me: I was debugging why a script worked on my machine but failed on a colleague’s, and it turned out a variable I assumed was globally set simply wasn’t there on his system. Environment variables are one of those foundational concepts that seem simple on the surface but have real depth once you start relying on them for configuration, automation, and scripting.

In this guide, I’ll cover what environment variables actually are, how they differ from regular shell variables, how to create and export them, and how to use them effectively in scripts and real projects.

What Is an Environment Variable?

An environment variable is a named value stored in the shell’s environment that can be accessed by the shell itself and by any programs or scripts it launches. Think of it as a piece of configuration data available system-wide (or session-wide) rather than something local to a single script.

Common examples you’ve probably already seen:

echo $HOME
echo $PATH
echo $USER
echo $SHELL

These are set automatically when your shell starts, and countless programs rely on them to behave correctly.

Environment Variables vs. Shell Variables

This distinction trips up a lot of beginners, so let’s be precise:

Example:

MY_VAR="hello"
echo $MY_VAR       # works, prints "hello"
bash -c 'echo $MY_VAR'   # prints nothing, because it's not exported

Now with export:

export MY_VAR="hello"
bash -c 'echo $MY_VAR'   # prints "hello"

The second command spawns a new Bash process, and because MY_VAR was exported, that child process inherits it.

Viewing Existing Environment Variables

To see all currently exported environment variables:

printenv

or:

env

To check a single variable:

printenv PATH

or simply:

echo $PATH

Setting a Variable for the Current Session

export EDITOR="nano"

Now any program that checks the EDITOR variable (like crontab -e or git commit) will open nano instead of whatever the system default is.

This setting only lasts for your current terminal session unless you make it permanent (covered below).

Setting a Variable Temporarily for a Single Command

Sometimes you only want a variable set for one specific command, without affecting the whole session:

MY_VAR="temporary" ./script.sh

This sets MY_VAR only in the environment of script.sh and doesn’t persist afterward or affect your interactive shell.

Making Environment Variables Permanent

To persist variables across sessions, add export statements to your shell configuration file, typically ~/.bashrc for interactive shells or ~/.bash_profile / ~/.profile for login shells.

nano ~/.bashrc

Add:

export EDITOR="vim"
export PATH="$HOME/scripts:$PATH"
export NODE_ENV="development"

Reload:

source ~/.bashrc

Why We Prepend to PATH Like That

Notice export PATH="$HOME/scripts:$PATH". This takes the existing PATH value and adds your custom scripts directory in front of it. Order matters here — directories listed earlier are searched first, so this ensures your custom scripts take priority over system binaries with the same name.

Common Built-In Environment Variables

VariablePurpose
HOMEPath to the current user’s home directory
PATHList of directories searched for executable commands
USERCurrent logged-in username
SHELLPath to the user’s default shell
PWDCurrent working directory
LANGSystem language and locale settings
EDITORDefault text editor for command-line tools
HISTSIZENumber of commands kept in shell history

Using Environment Variables in Scripts

Here’s a small script that demonstrates practical use:

#!/bin/bash

# Use an environment variable with a fallback default
LOG_DIR="${LOG_DIR:-/var/log/myapp}"

mkdir -p "$LOG_DIR"
echo "Logging to $LOG_DIR" >> "$LOG_DIR/app.log"

Let’s break this down:

This pattern is extremely common in real-world scripts because it lets the same script adapt to different environments (development, staging, production) just by changing an environment variable, without touching the script’s code.

Unsetting a Variable

unset MY_VAR

This removes the variable entirely from the current session, including from the environment if it was exported.

Real-World Use Cases

Configuration for applications: Node.js, Python, and many frameworks read variables like NODE_ENV, DATABASE_URL, or API_KEY from the environment rather than hardcoding them into source code — this keeps secrets out of your codebase.

Docker and containers: Environment variables are the standard way to configure containers:

docker run -e DATABASE_URL="postgres://localhost/mydb" myapp

CI/CD pipelines: Build systems like GitHub Actions or Jenkins inject secrets and configuration as environment variables so scripts can access credentials without exposing them in code.

Switching between environments:

export APP_ENV="staging"
./deploy.sh

The deploy script can then branch its behavior based on $APP_ENV.

Using .env Files

Many projects store environment variables in a .env file and load them at runtime rather than exporting them manually every session. Here’s a simple way to load one in Bash:

set -a
source .env
set +a

A typical .env file looks like:

DATABASE_URL=postgres://localhost/mydb
API_KEY=your_api_key_here
DEBUG=true

Best Practices

Security Considerations

Optimization Tips

Troubleshooting Common Issues

Variable not available in a script but works in the terminal: The variable likely wasn’t exported. Use export VAR_NAME=value instead of just VAR_NAME=value.

Variable set in .bashrc doesn’t apply to cron jobs: Cron runs with a minimal environment and doesn’t source .bashrc. Set variables explicitly at the top of the crontab or inside the script itself.

Changes to .bashrc don’t seem to take effect: Make sure you’re editing the right file for your shell type (interactive vs. login shell), and remember to source it or open a new terminal.

PATH seems broken after editing it: Double-check you didn’t overwrite PATH entirely instead of appending to it — always include $PATH in the new value.

Frequently Asked Questions

What’s the difference between .bashrc and .bash_profile? .bashrc runs for interactive non-login shells (like opening a new terminal tab), while .bash_profile (or .profile) runs for login shells (like SSH sessions). Many setups source one from the other to keep behavior consistent.

Can environment variables be arrays or complex data? No, environment variables are always simple strings. For complex data, use a config file format like JSON or YAML and parse it in your script.

Do environment variables persist after a reboot? Only if they’re defined in a file that’s sourced at shell startup, like ~/.bashrc or /etc/environment.

How do I set a system-wide environment variable for all users? Add it to /etc/environment or /etc/profile.d/custom.sh, which apply to all users rather than just your account.

Common Mistakes to Avoid

Summary

Environment variables are the backbone of configuration in shell scripting and application development. Once you understand the difference between shell variables and exported environment variables, and how to persist them in your configuration files, you can build flexible scripts and applications that adapt to different environments without hardcoding values. Combine this with .env files and sensible defaults, and you’ve got a solid, portable configuration strategy.

References

Exit mobile version