BLOG POSTS
    MangoHost Blog / How to Read and Set Environmental and Shell Variables on Linux
How to Read and Set Environmental and Shell Variables on Linux

How to Read and Set Environmental and Shell Variables on Linux

Environmental variables and shell variables are fundamental components of Linux systems that store configuration data, system paths, and user preferences. Understanding how to read, set, and manage these variables is crucial for developers and system administrators who need to configure applications, automate deployments, or troubleshoot system issues. This guide will walk you through the technical details of working with environment variables, from basic commands to advanced configuration scenarios that you’ll encounter in production environments.

Understanding Environment vs Shell Variables

Before diving into commands, it’s important to understand the distinction between shell variables and environment variables. Shell variables exist only within the current shell session and aren’t passed to child processes. Environment variables, however, are exported to child processes and are available system-wide.

Shell variables are local to your current session:

# Setting a shell variable
MY_VAR="hello world"
echo $MY_VAR

Environment variables are exported and inherited by child processes:

# Setting an environment variable
export MY_ENV_VAR="hello world"
echo $MY_ENV_VAR

The key difference becomes apparent when you spawn a new shell or run a script. Shell variables won’t be available in the child process, but environment variables will be.

Reading Environment and Shell Variables

Linux provides several methods to view and access variables. Here are the most commonly used approaches:

Using the env Command

The env command displays all environment variables in the current session:

# Display all environment variables
env

# Filter specific variables
env | grep PATH

# Display variables in sorted order
env | sort

Using printenv

The printenv command is specifically designed for environment variables:

# Show all environment variables
printenv

# Show specific variable
printenv PATH

# Show multiple variables
printenv PATH HOME USER

Using set Command

The set command shows both environment and shell variables:

# Display all variables (shell and environment)
set

# Display only environment variables (bash)
set -o posix; set; set +o posix

Accessing Variables in Scripts

In shell scripts and command line, you access variables using the dollar sign syntax:

# Direct access
echo $HOME
echo $PATH

# Using curly braces (recommended for clarity)
echo ${HOME}
echo ${PATH}

# Default values if variable is unset
echo ${MY_VAR:-"default value"}

# Check if variable is set
if [ -n "$MY_VAR" ]; then
    echo "Variable is set: $MY_VAR"
else
    echo "Variable is not set"
fi

Setting Environment and Shell Variables

There are multiple ways to set variables depending on your specific needs and the scope you want to achieve.

Temporary Variables (Current Session Only)

These variables exist only for the current shell session:

# Shell variable (not exported)
MY_SHELL_VAR="temporary value"

# Environment variable (exported)
export MY_ENV_VAR="temporary environment value"

# Set and export in one line
export DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"

Persistent Variables for User Sessions

To make variables persistent across login sessions, add them to shell configuration files:

# For bash users - add to ~/.bashrc
echo 'export MY_PERMANENT_VAR="persistent value"' >> ~/.bashrc

# For zsh users - add to ~/.zshrc
echo 'export MY_PERMANENT_VAR="persistent value"' >> ~/.zshrc

# Reload the configuration
source ~/.bashrc
# or
source ~/.zshrc

System-wide Environment Variables

For system-wide variables available to all users:

# Add to /etc/environment (Ubuntu/Debian)
sudo echo 'GLOBAL_VAR="system wide value"' >> /etc/environment

# Add to /etc/profile for all users
sudo echo 'export GLOBAL_VAR="system wide value"' >> /etc/profile

# Create custom file in /etc/profile.d/
sudo echo 'export CUSTOM_VAR="value"' > /etc/profile.d/custom-vars.sh

Real-world Use Cases and Examples

Here are practical scenarios where environment variables are essential:

Database Configuration

# Setting database connection variables
export DB_HOST="localhost"
export DB_PORT="5432"
export DB_NAME="production_db"
export DB_USER="app_user"
export DB_PASSWORD="secure_password"

# Using in application
psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME

API Keys and Secrets

# Setting API credentials
export API_KEY="your-secret-api-key"
export AWS_ACCESS_KEY_ID="your-aws-access-key"
export AWS_SECRET_ACCESS_KEY="your-aws-secret-key"

# Using in scripts
curl -H "Authorization: Bearer $API_KEY" https://api.example.com/data

Development Environment Setup

# Node.js environment
export NODE_ENV="development"
export PORT="3000"

# Python environment
export PYTHONPATH="/opt/myapp:$PYTHONPATH"
export FLASK_ENV="development"

# Java environment
export JAVA_HOME="/usr/lib/jvm/java-11-openjdk"
export MAVEN_HOME="/opt/maven"
export PATH="$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH"

Advanced Variable Management Techniques

Variable Substitution and Manipulation

Bash provides powerful variable manipulation capabilities:

# String length
echo ${#PATH}

# Substring extraction
echo ${PATH:0:10}    # First 10 characters
echo ${PATH:10}      # From 10th character to end

# Pattern matching and replacement
echo ${PATH//:/\n}   # Replace all colons with newlines
echo ${PATH%:*}      # Remove everything after last colon
echo ${PATH#*:}      # Remove everything before first colon

# Case conversion (Bash 4+)
export UPPER_VAR="hello world"
echo ${UPPER_VAR^^}  # Convert to uppercase
echo ${UPPER_VAR,,}  # Convert to lowercase

Array Variables

Bash supports array variables for more complex data structures:

# Declare array
declare -a SERVERS=("web1.example.com" "web2.example.com" "web3.example.com")

# Access array elements
echo ${SERVERS[0]}    # First element
echo ${SERVERS[@]}    # All elements
echo ${#SERVERS[@]}   # Array length

# Loop through array
for server in "${SERVERS[@]}"; do
    echo "Processing server: $server"
    # ping -c 1 $server
done

Conditional Variable Setting

# Set variable only if not already set
: ${PORT:=8080}
: ${DATABASE_URL:="sqlite:///default.db"}

# Set variable and export if not set
export PORT=${PORT:-8080}
export ENV=${ENV:-development}

# Require variable to be set
: ${REQUIRED_VAR:?Error: REQUIRED_VAR must be set}

Environment Variable Security Considerations

Working with sensitive data in environment variables requires careful attention to security:

Best Practices for Secrets

  • Never commit environment files with secrets to version control
  • Use tools like direnv or dotenv for local development
  • Implement proper access controls on configuration files
  • Use secrets management services in production environments
# Create a .env file (never commit this)
cat > .env << EOF
DATABASE_PASSWORD=super_secret_password
API_KEY=secret_api_key
JWT_SECRET=jwt_signing_secret
EOF

# Set proper permissions
chmod 600 .env

# Load variables from file (using a script)
if [ -f .env ]; then
    export $(cat .env | grep -v '^#' | xargs)
fi

Using systemd for Service Environment Variables

For services managed by systemd, environment variables can be set in service files:

# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target

[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/start
Environment=NODE_ENV=production
Environment=PORT=3000
EnvironmentFile=/etc/myapp/environment
Restart=always

[Install]
WantedBy=multi-user.target

Troubleshooting Common Issues

Here are solutions to frequent problems you'll encounter:

Variables Not Persisting

If variables disappear after closing the terminal:

# Check which shell you're using
echo $SHELL

# Verify the correct configuration file
ls -la ~/.bashrc ~/.bash_profile ~/.zshrc ~/.profile

# Check if files are being sourced
echo "echo 'Loading .bashrc'" >> ~/.bashrc

# Force reload configuration
source ~/.bashrc

PATH Variable Issues

When commands aren't found after modifying PATH:

# Check current PATH
echo $PATH

# Verify directory exists and has executable files
ls -la /usr/local/bin

# Add to PATH safely (avoiding duplicates)
case ":$PATH:" in
    *:/usr/local/bin:*) ;;
    *) PATH="/usr/local/bin:$PATH" ;;
esac
export PATH

# Reset PATH if corrupted
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

Variable Expansion Problems

When variables aren't expanding correctly:

# Use quotes to preserve spaces
MY_VAR="value with spaces"
echo "$MY_VAR"

# Use single quotes to prevent expansion
echo 'The variable $HOME contains: ' "$HOME"

# Debug variable expansion
set -x  # Enable debug mode
echo $MY_VAR
set +x  # Disable debug mode

Performance and System Impact

Environment variables have minimal performance impact, but there are considerations for large-scale deployments:

Aspect Impact Recommendation
Memory Usage ~1KB per 1000 variables Limit to necessary variables
Process Startup Negligible delay No specific optimization needed
Inheritance All exported variables copied to child processes Unset unused variables in long-running processes
Security Variables visible in process lists Use files or external secret managers for sensitive data

Integration with Container Environments

Environment variables are crucial in containerized environments and cloud deployments:

Docker Integration

# Dockerfile
ENV NODE_ENV=production
ENV PORT=3000

# Docker run with environment variables
docker run -e NODE_ENV=production -e DATABASE_URL=postgres://... myapp

# Using environment file
docker run --env-file .env myapp

Kubernetes ConfigMaps and Secrets

# ConfigMap example
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  NODE_ENV: "production"
  LOG_LEVEL: "info"

# Using in Pod
spec:
  containers:
  - name: app
    envFrom:
    - configMapRef:
        name: app-config

For production deployments on dedicated infrastructure, consider using dedicated servers that provide full control over environment configuration, or VPS services for flexible containerized deployments.

Useful Tools and Utilities

Several tools can enhance your environment variable management:

  • direnv: Automatically loads environment variables based on directory
  • envsubst: Substitutes environment variables in template files
  • dotenv: Libraries for various programming languages to load .env files
  • systemd-environment-d-generator: System-wide environment variable management
# Install direnv (Ubuntu/Debian)
sudo apt install direnv

# Create .envrc file in project directory
echo 'export DATABASE_URL="postgresql://localhost/mydb"' > .envrc
direnv allow

# Using envsubst for template processing
echo 'Database: ${DATABASE_URL}' | envsubst

For additional information on environment variable best practices, consult the GNU Bash Manual and the POSIX Environment Variables specification.



This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.

This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.

Leave a reply

Your email address will not be published. Required fields are marked