Environment variables provide a powerful way to configure, customize, and control the environment in Bash and other shells on Linux, Unix, and macOS systems. This comprehensive guide examines environment variables in-depth – how they work, when to use them, best practices, and more.
What Are Environment Variables and Why Do They Matter?
Environment variables are named values that can influence the way running processes behave on a Linux or other Unix-like operating system.
Some common examples include:
- HOME – The path to the user‘s home directory
- PATH – A list of directories to search for executables
- PWD – The current working directory
Over the last decade, environment variables have become an integral part of modern software development workflows. A 2021 survey found that over 75% of professional developers rely on environment variables for app configuration and customization.
Environment variables enable processes to be configured without hard coding details. This makes reuse and portability easier since the main logic is separated from system-specific values.
Many programs and Bash itself utilize variables to operate correctly or locate required resources. For instance, Bash uses the PATH variable to search directories when executing commands.
Overall, environment variables are a critical aspect of Linux environments – expanding customization, simplifying deployment, and preventing repeat code. Understanding how to effectively use them is an essential skill for developers, DevOps engineers, sysadmins, and power users.
Viewing and Inspecting Current Environment Variables
Before utilizing environment variables, it helps to understand what is already defined in your shell session.
There are several handy commands to display environment variable contents:
printenv
View all defined variables:
printenv
env
Identical output to printenv:
env
set
Show variables + shell functions and definitions:
set
echo
Print a specific variable‘s value by prefixing it with a $:
echo $PATH
Inspecting existing environment contents reveals variables available for use in scripts and programs. It also shows expected variable names in case you need to add your own.
Now let‘s look at how to define new variables or modify those already set…
Setting and Unsetting Variables in Bash
Environment variables can be set, unset, and exported within Bash scripts or interactively within shells. The scope and lifespan of a variable depends how it is defined.
Export
The export command sets a new variable and exports it into the environments of child processes:
export MYVAR="some value"
MYVAR is now accessible from subprocesses of this shell. But it will not persist when starting new shell sessions.
Verify it is set:
echo $MYVAR
Unset
Remove a previously set variable from the current shell‘s env:
unset MYVAR
Check if unset:
echo $MYVAR
No output means it has been cleared.
Persisting Variables Across Sessions
There are several Bash startup scripts that can define variables scoped across shells and logins:
~/.bashrc
This script runs for interactive non-login shells. Place variable exports here to make them available in new interactive subshells:
export EDITOR=vim
~/.bash_profile
For login shells like when opening a new terminal, .bash_profile runs instead of .bashrc. Variable exports here apply at start of new login sessions:
export PATH=$PATH:/opt/bin
Now /opt/bin is permanently added to the PATH.
/etc/environment
This is a global system-level file defining user-agnostic variables. Only the root user can edit it.
Example:
JAVA_HOME="/usr/lib/jvm/java-17"
Sets default Java version for all users system-wide.
These files allow persisting values between shell invocations and logins.
Common Environment Variables on Linux
While any variable can be created, some have defined meanings across Linux conventions and programs.
PATH
Lists directories searched for commands when entered. If a folder in PATH contains an executable matching the command, it is launched.
PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games
This PATH means search these folders for executables.
HOME
Specifies path to the current user‘s home directory. Referenced in Bash using shorthand ~
PWD
Holds working directory a user is currently located in.
USER
Contains the current logged in username.
LANG
Controls system language and localization settings like timezone and formatting.
PS1
Dictates Bash prompt string appearance shown in the shell. Adds colors, for example.
HISTSIZE
Limit on how many previously run commands are stored in history file.
Defines location of user‘s mailbox file. Used by mail clients.
There are many standard variables defined by Linux like these. Programs can also reference their own custom variables.
Diving Into How Environment Variables Work
While using environment variables in Bash is straightforward, understanding what happens behind the scenes explains how they interact with processes.
At the OS level, environments are represented by key-value string pairs stored in the process memory image similarly to other program data. But these memory regions are designated as the environment.
When a new process starts, it inherits a copy of its parent‘s environment. This allows child processes to access the same set of environment variables. Multiple descending processes can all share this environment state.
The OS exec() system calls used to start new programs allow optionally specifying a custom set of environment variables instead of inheriting the parent‘s. This enables fine-grained control of each process‘s environment.
In shells like Bash, commands like export and startup files amend the inherited environment for all subsequent child processes. So modifications persist across programs invoked from that shell.
By contrast, altering environment contents directly via OS interfaces impacts only a single process. This demonstrates the inheritability that makes environment variables useful compared to other component communication techniques.
Overall, manipulating environment data enables configuring multiple downstream processes without coding the parameters directly into the programs. Underlying OS memory sharing mechanisms then propagate the changes.
Comparing Environment Variables to Configuration Files
Another common approach to customizing programs and server processes is using startup configuration files like .conf or .yaml formats.
Compared to configuration files, environment variables have several advantages:
Simplicity – No parsing or loading complex file formats. Just set a string value.
Dynamic Control – Can be modified on-the-fly without restarting services.
Guaranteed Inheritance – Automagically passed to all child processes.
Loose Coupling – Not tied to rigid schemas or file location on disk.
Portability – Travels between environments and layers, local or remote.
Flexibility – Ad-hoc usages for user preferences or temporary contexts possible.
However configuration files have benefits around:
Organization – Related configuration grouped logically.
Comments / Documentation – Notes can explain usage directly in file.
Validation – Contents can be schema validated.
Filesystem Snapshots / Rollbacks – Full history via source control.
In summary, environment variables are better suited for dynamic configuration needing to flow between layers and systems. Configuration files win for complex strongly structured data requiring history and validation.
Knowing these trade-offs helps select what fits best in a given situation.
Security Considerations With Environment Variables
While extremely useful, it‘s important to be aware environment variables do involve security risks in some scenarios – especially environments with untrusted users running potentially malicious programs.
Some dangers posed:
- Sensitive Leaks – Data in environments may end up visible when child processes print their env contents.
- PATH Poisoning – Inserting bad directories into PATH could enable hijacking normal command executions later.
- Environment Variable Overuse – Configuring apps too heavily via env variables instead of files removes auditing and validation.
- Injection Issues – If building configs by string concatenating untrusted input sources without sanitization.
- Operational Errors – Developers accidentally overriding important variables used internally by the OS or apps leading to failures.
So while powerful, environment variables should be used wisely – avoiding exposing secrets and potentially hostile settings in production systems.
Industry Standard Usage Patterns
Beyond ad-hoc script configuration, environment variables now feature prominently in standardized application configuration systems used by enterprise platforms:
12-Factor App Methodology – Influential paradigm dictating best practices for modern apps. Formalizes many usages.
Kubernetes ConfigMaps – Environment customization system providing containers options for app configuration declarative settings instead of hardcoded values.
Docker Env Vars – Used both at build time and passed into containers at runtime to inject preferences.
Serverless Platforms – Environment variables enable function configuration in Lambda, Cloud Functions.
CI/CD Pipelines – Jenkins, CircleCI, Travis all leverage env variables for job customization.
Environment variables are now a critical aspect of multi-layer distributed applications – facilitating configuration customization across processes, containers, functions, and hosts.
Example Practical Applications
Beyond background theory, real-world usage demonstrates the power of environment variables best:
Script Configuration
Customize script base URL on each run:
#!/bin/bash
url="https://example.com"
if [ "$BASE_URL" ]; then
url="$BASE_URL"
fi
echo "URL is $url"
Invoke with:
BASE_URL="http://test.local" ./myscript.sh
User Customization
Change Bash prompt colors without modifying RC files:
export PS1="[\[$(tput setaf 2)\]\u\[$(tput sgr0)\]@\[$(tput setaf 4)\]\h\[$(tput sgr0)\]]\$ "
Allows simple prompt formatting.
Temporary Environment
Modify PATH only for a single command invocation:
env PATH="/pyenv/shims:/usr/bin:$PATH" pyenv install 3.9.0
Avoids persisting PATH changes.
Application Configuration
Java heap size via environment variable:
export JAVA_OPTS="-Xmx2048m"
java MyApp
Sets JVM max memory to 2GB without a config file.
These examples demonstrate versatile operational situations where environment variables may be the best fit over alternatives.
Key Takeaways
Whether just starting out or an experienced developer, remembering these key facts and uses makes tapping into the power of environment variables much easier:
- Automatic inheritance to child processes enables configuration without coding every detail.
- Standard variables like PATH have defined purposes, but any name can be used.
- Special startup scripts load configurations across login sessions.
- Environment data allows communication across layers and system boundaries.
- Security matters when working with untrusted code or users.
- Environment variables now feature heavily in standardized application patterns and tooling.
- Use for user preferences, script parameters, temporary contexts, and application-centric configurations provides flexibility.
Learning to effectively leverage environment variables unlocks additional functionality from Linux, Bash, containers, cloud platforms, and more – making them well worth understanding inside and out.
The ability to properly view, set, and manage environment variables in Bash is an essential skill for engineers on Linux or Unix systems working in the cloud, DevOps, site reliability, or development spheres.


