Environment Variables: Setting and Exporting in Linux/Unix Systems
Introduction
Environment variables are dynamic named values that can affect the way running processes behave on a computer. They are part of the environment in which a process runs and can be used to pass configuration information to applications, store system-wide settings, and customize the behavior of the shell and other programs.
This comprehensive guide covers the concepts, methods, and best practices for setting and exporting environment variables in Linux and Unix-like systems.
What are Environment Variables?
Environment variables are key-value pairs that are available system-wide and can be accessed by any process running on the system. They serve several important purposes:
- Configuration Storage: Store configuration data that applications can read - System Information: Provide information about the system environment - Path Management: Define where the system should look for executable files - User Preferences: Store user-specific settings and preferences - Security: Store sensitive information like API keys and credentials
Types of Variables
There are two main types of variables in shell environments:
1. Shell Variables: Available only to the current shell session 2. Environment Variables: Available to the current shell and all child processes
Basic Concepts and Terminology
Variable Scope
Variables can have different scopes depending on how they are defined:
| Scope Type | Description | Visibility | Persistence | |------------|-------------|------------|-------------| | Local | Defined within a function or script | Current function/script only | Until function/script ends | | Shell | Defined in current shell session | Current shell only | Until shell session ends | | Environment | Exported variables | Current shell and child processes | Until shell session ends | | Global | System-wide variables | All users and processes | Persistent across reboots |
Variable Naming Conventions
Environment variables follow specific naming conventions:
- Use uppercase letters for environment variables - Use underscores to separate words - Start with a letter or underscore - Contain only letters, numbers, and underscores - Avoid spaces and special characters
Examples of valid variable names:
- PATH
- HOME
- USER_PREFERENCES
- DB_CONNECTION_STRING
- _PRIVATE_VAR
Setting Environment Variables
Method 1: Direct Assignment
The most basic way to set a variable is through direct assignment:
`bash
VARIABLE_NAME=value
`
Example:
`bash
MY_APP_CONFIG=/etc/myapp/config.conf
DATABASE_URL=postgresql://localhost:5432/mydb
`
Notes: - No spaces around the equals sign - Values with spaces must be quoted - This creates a shell variable, not an environment variable
Method 2: Using the export Command
To make a variable available to child processes, use the export command:
`bash
export VARIABLE_NAME=value
`
Example:
`bash
export PATH=/usr/local/bin:$PATH
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk
`
Method 3: Two-Step Process
You can also set a variable and then export it separately:
`bash
VARIABLE_NAME=value
export VARIABLE_NAME
`
Example:
`bash
API_KEY=abc123def456
export API_KEY
`
Viewing Environment Variables
Command: env
The env command displays all environment variables:
`bash
env
`
Output example:
`
PATH=/usr/local/bin:/usr/bin:/bin
HOME=/home/username
USER=username
SHELL=/bin/bash
`
Command: printenv
Similar to env, but with additional options:
`bash
printenv
printenv VARIABLE_NAME
`
Examples:
`bash
Display all environment variables
printenvDisplay specific variable
printenv PATHDisplay multiple specific variables
printenv PATH HOME USER`Command: echo
Display the value of a specific variable:
`bash
echo $VARIABLE_NAME
`
Examples:
`bash
echo $PATH
echo $HOME
echo $USER
`
Command: set
Display all variables (both shell and environment):
`bash
set
`
Note: This command shows more output than env because it includes shell variables and functions.
Common Environment Variables
System Variables
| Variable | Description | Example Value |
|----------|-------------|---------------|
| PATH | Directories to search for executables | /usr/local/bin:/usr/bin:/bin |
| HOME | User's home directory | /home/username |
| USER | Current username | john |
| SHELL | Default shell | /bin/bash |
| PWD | Present working directory | /home/user/documents |
| OLDPWD | Previous working directory | /home/user |
| TERM | Terminal type | xterm-256color |
| LANG | System language | en_US.UTF-8 |
Application-Specific Variables
| Variable | Description | Example Value |
|----------|-------------|---------------|
| JAVA_HOME | Java installation directory | /usr/lib/jvm/java-11-openjdk |
| PYTHONPATH | Python module search path | /usr/local/lib/python3.8/site-packages |
| NODE_ENV | Node.js environment | production |
| DATABASE_URL | Database connection string | postgresql://user:pass@localhost/db |
| API_KEY | API authentication key | sk-1234567890abcdef |
Persistent Environment Variables
User-Level Persistence
To make environment variables persistent for a specific user, add them to shell configuration files:
#### Bash Configuration Files
| File | Purpose | When Loaded |
|------|---------|-------------|
| ~/.bashrc | Interactive non-login shells | Every new terminal |
| ~/.bash_profile | Login shells | Login only |
| ~/.profile | POSIX-compliant login shells | Login (all shells) |
| ~/.bash_login | Bash login shells | Login (if no .bash_profile) |
Example ~/.bashrc:
`bash
Custom environment variables
export EDITOR=vim export BROWSER=firefox export JAVA_HOME=/usr/lib/jvm/java-11-openjdk export PATH=$PATH:$HOME/bin:$HOME/.local/binApplication-specific variables
export NODE_ENV=development export DATABASE_URL=postgresql://localhost:5432/myapp`#### Zsh Configuration
For Zsh users, use ~/.zshrc:
`bash
~/.zshrc
export EDITOR=vim export PATH=$PATH:$HOME/bin export PYTHONPATH=$PYTHONPATH:$HOME/python-libs`System-Level Persistence
For system-wide environment variables, modify these files:
#### /etc/environment
Simple key-value pairs (Ubuntu/Debian):
`bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
JAVA_HOME="/usr/lib/jvm/java-11-openjdk"
EDITOR="vim"
`
Notes:
- No export keyword needed
- Values must be quoted
- No variable expansion
#### /etc/profile
System-wide profile for all users:
`bash
/etc/profile
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk export PATH=$PATH:$JAVA_HOME/bin export EDITOR=vim`#### /etc/bash.bashrc
System-wide bashrc:
`bash
/etc/bash.bashrc
export HISTSIZE=10000 export HISTFILESIZE=20000 export EDITOR=vim`Advanced Techniques
Variable Expansion and Substitution
#### Basic Expansion
`bash
export PATH=$PATH:/new/directory
export FULL_NAME="$FIRST_NAME $LAST_NAME"
`
#### Parameter Expansion
| Syntax | Description | Example |
|--------|-------------|---------|
| ${VAR} | Basic expansion | ${HOME}/documents |
| ${VAR:-default} | Use default if unset | ${PORT:-8080} |
| ${VAR:=default} | Set default if unset | ${CONFIG:=/etc/app.conf} |
| ${VAR:+alternate} | Use alternate if set | ${DEBUG:+--verbose} |
| ${VAR:?error} | Error if unset | ${REQUIRED:?Variable required} |
Examples:
`bash
Set default port if not specified
export PORT=${PORT:-3000}Set configuration file with default
export CONFIG_FILE=${CONFIG_FILE:=/etc/myapp/config.json}Add debug flag if DEBUG is set
COMMAND="myapp ${DEBUG:+--debug} --config $CONFIG_FILE"`Conditional Variable Setting
`bash
Set variable only if not already set
if [ -z "$JAVA_HOME" ]; then export JAVA_HOME=/usr/lib/jvm/default-java fiSet variable based on system type
if [ "$(uname)" = "Darwin" ]; then export JAVA_HOME=/Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home else export JAVA_HOME=/usr/lib/jvm/java-11-openjdk fi`Array Variables
Bash supports array variables:
`bash
Declare array
declare -a SERVERS=("web1.example.com" "web2.example.com" "web3.example.com")Export array (as string)
export SERVER_LIST="${SERVERS[*]}"Access array elements
echo "First server: ${SERVERS[0]}" echo "All servers: ${SERVERS[@]}"`Environment Variables in Different Contexts
Shell Scripts
When using environment variables in shell scripts:
`bash
#!/bin/bash
Check if required variables are set
if [ -z "$DATABASE_URL" ]; then echo "Error: DATABASE_URL environment variable is required" exit 1 fiUse variables with defaults
LOG_LEVEL=${LOG_LEVEL:-INFO} PORT=${PORT:-8080}Export variables for child processes
export APP_ENV=production export LOG_FILE=/var/log/myapp.logRun application with environment
exec myapp --port "$PORT" --log-level "$LOG_LEVEL"`Process Substitution
Environment variables can be set for specific commands:
`bash
Set variable for single command
ENV_VAR=value commandMultiple variables for single command
VAR1=value1 VAR2=value2 commandExamples
DEBUG=1 node app.js PORT=3000 npm start RAILS_ENV=production bundle exec rails server`Subprocess Environment
`bash
Create clean environment
env -i commandRun with specific environment
env VAR1=value1 VAR2=value2 commandRemove specific variables
env -u UNWANTED_VAR command`Security Considerations
Sensitive Information
Best Practices:
- Never store passwords or API keys in shell history
- Use secure methods to pass sensitive variables
- Limit access to configuration files containing secrets
- Use tools like direnv or secret management systems
Example secure variable setting:
`bash
Read password securely
read -s -p "Enter database password: " DB_PASSWORD export DB_PASSWORDOr use a secure file
export DB_PASSWORD=$(cat /secure/path/db_password)`Variable Validation
`bash
Validate required variables
validate_env() { local required_vars=("DATABASE_URL" "API_KEY" "SECRET_KEY") local missing_vars=() for var in "${required_vars[@]}"; do if [ -z "${!var}" ]; then missing_vars+=("$var") fi done if [ ${#missing_vars[@]} -ne 0 ]; then echo "Error: Missing required environment variables: ${missing_vars[*]}" return 1 fi }Call validation function
validate_env || exit 1`Troubleshooting Common Issues
Issue 1: Variables Not Available in Child Processes
Problem: Variable set but not accessible in subshells or child processes.
Solution: Use export to make variables available to child processes:
`bash
Wrong
MY_VAR=valueCorrect
export MY_VAR=value`Issue 2: Variables Not Persisting
Problem: Variables disappear when terminal is closed.
Solution: Add variables to appropriate configuration files:
`bash
Add to ~/.bashrc or ~/.profile
echo 'export MY_VAR=value' >> ~/.bashrc source ~/.bashrc`Issue 3: Path Issues
Problem: Commands not found after modifying PATH.
Solution: Verify PATH syntax and order:
`bash
Check current PATH
echo $PATHCorrect way to add to PATH
export PATH=/new/directory:$PATHVerify the change
which command_name`Issue 4: Variable Expansion Issues
Problem: Variables not expanding correctly.
Solutions:
`bash
Use quotes for variables with spaces
export MY_PATH="$HOME/My Documents"Use braces for clarity
export FULL_PATH="${HOME}/bin:${PATH}"Debug variable expansion
set -x # Enable debug mode echo $MY_VAR set +x # Disable debug mode`Best Practices
Naming Conventions
- Use descriptive, uppercase names for environment variables - Group related variables with common prefixes - Follow application-specific conventionsExamples:
`bash
Good naming
export DB_HOST=localhost export DB_PORT=5432 export DB_NAME=myapp export DB_USER=appuserApplication-specific grouping
export MYAPP_CONFIG_DIR=/etc/myapp export MYAPP_LOG_LEVEL=INFO export MYAPP_DEBUG_MODE=false`Documentation
Document environment variables in your projects:`bash
Create .env.example file
DB_HOST=localhost DB_PORT=5432 DB_NAME=example_db API_KEY=your_api_key_here DEBUG=false`Configuration Management
Use configuration management tools for complex environments:- direnv: Automatically load environment variables based on directory
- dotenv: Load environment variables from .env files
- Docker: Use environment variables in containers
- Kubernetes: ConfigMaps and Secrets
Example with direnv:
`bash
.envrc file
export DATABASE_URL=postgresql://localhost:5432/myapp export API_KEY=development_key export DEBUG=trueAllow the .envrc file
direnv allow`Practical Examples
Web Development Environment
`bash
~/.bashrc
export NODE_ENV=development export PORT=3000 export DATABASE_URL=postgresql://localhost:5432/webapp export REDIS_URL=redis://localhost:6379 export JWT_SECRET=development_secret export API_BASE_URL=http://localhost:3000/api`Java Development Environment
`bash
~/.profile
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk export MAVEN_HOME=/opt/maven export GRADLE_HOME=/opt/gradle export PATH=$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin:$GRADLE_HOME/bin export MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=256m"`Python Development Environment
`bash
~/.bashrc
export PYTHONPATH=$PYTHONPATH:$HOME/python-projects export VIRTUAL_ENV_DISABLE_PROMPT=1 export PIP_REQUIRE_VIRTUALENV=true export PYTHONDONTWRITEBYTECODE=1`DevOps Environment
`bash
~/.profile
export KUBECONFIG=$HOME/.kube/config export TERRAFORM_LOG=INFO export AWS_DEFAULT_REGION=us-west-2 export DOCKER_BUILDKIT=1 export COMPOSE_DOCKER_CLI_BUILD=1`Conclusion
Environment variables are a fundamental concept in Unix-like systems that provide a flexible way to configure applications and system behavior. Understanding how to properly set, export, and manage environment variables is crucial for system administration, software development, and automation tasks.
Key takeaways:
- Use export to make variables available to child processes
- Choose appropriate configuration files for persistence
- Follow naming conventions and security best practices
- Document your environment variables for team collaboration
- Use tools and frameworks to manage complex configurations
By mastering environment variables, you can create more flexible, configurable, and maintainable systems and applications.