Shell Variables

Understanding and managing variables in Linux shell environments

Basic Syntax: VARIABLE_NAME=value
export VARIABLE_NAME=value
echo $VARIABLE_NAME

Description

Shell variables are fundamental components of Linux shell environments that store data values for use by the shell and programs. They can be local to the current shell session or exported as environment variables to be inherited by child processes. Understanding variables is essential for shell scripting, system configuration, and effective command-line usage.

Note: Variable names are case-sensitive and by convention are often written in uppercase for environment variables and lowercase for local variables.

Types of Variables

Type Scope Description
Local Variables Current shell only Available only in the current shell session
Environment Variables Current shell and children Exported to child processes and subshells
Special Variables Shell-specific Built-in variables with special meanings
Positional Parameters Script/function Command-line arguments and function parameters

Creating and Using Variables

Basic variable assignment:
# Create a local variable
MY_VAR="Hello World"
echo $MY_VAR
# Output: Hello World

# No spaces around the equals sign!
NAME="John Doe"
echo "Welcome, $NAME"
# Output: Welcome, John Doe
Environment variables:
# Create and export in one step
export PATH="/usr/local/bin:$PATH"

# Create local, then export
MY_CONFIG="/etc/myapp.conf"
export MY_CONFIG

# Check if variable is exported
declare -p MY_CONFIG
# Output: declare -x MY_CONFIG="/etc/myapp.conf"
Variable expansion:
# Basic expansion
USER_HOME="/home/$USER"
echo $USER_HOME

# Brace expansion (recommended)
USER_HOME="/home/${USER}"
echo ${USER_HOME}

# Default values
echo ${UNDEFINED_VAR:-"default value"}
# Output: default value

Common Environment Variables

Variable Description Example Value
PATH Executable search path /usr/bin:/bin:/usr/local/bin
HOME User's home directory /home/username
USER Current username john
SHELL Current shell /bin/bash
PWD Present working directory /home/john/projects
OLDPWD Previous working directory /home/john
LANG System language/locale en_US.UTF-8
TERM Terminal type xterm-256color

Special Variables

Variable Description
$0 Name of the script or shell
$1, $2, ... Positional parameters (command-line arguments)
$# Number of positional parameters
$@ All positional parameters as separate words
$* All positional parameters as single word
$$ Process ID of current shell
$? Exit status of last command
$! Process ID of last background job

Variable Expansion Techniques

Parameter expansion:
# Default values
echo ${VAR:-default}        # Use default if VAR is unset
echo ${VAR:=default}        # Set VAR to default if unset
echo ${VAR:+alternative}    # Use alternative if VAR is set

# String length
NAME="John"
echo ${#NAME}               # Output: 4

# Substring extraction
TEXT="Hello World"
echo ${TEXT:0:5}            # Output: Hello
echo ${TEXT:6}              # Output: World
Pattern matching:
FILENAME="document.txt.backup"

# Remove shortest match from end
echo ${FILENAME%.*}         # Output: document.txt

# Remove longest match from end
echo ${FILENAME%%.*}        # Output: document

# Remove shortest match from beginning
echo ${FILENAME#*.}         # Output: txt.backup

# Remove longest match from beginning
echo ${FILENAME##*.}        # Output: backup
Case modification:
TEXT="Hello World"

# Convert to uppercase
echo ${TEXT^^}              # Output: HELLO WORLD

# Convert to lowercase
echo ${TEXT,,}              # Output: hello world

# Capitalize first letter
echo ${TEXT^}               # Output: Hello world

Working with Arrays

Array variables:
# Create an array
FRUITS=("apple" "banana" "orange")

# Access elements
echo ${FRUITS[0]}           # Output: apple
echo ${FRUITS[1]}           # Output: banana

# All elements
echo ${FRUITS[@]}           # Output: apple banana orange

# Array length
echo ${#FRUITS[@]}          # Output: 3

# Add elements
FRUITS+=("grape")
echo ${FRUITS[@]}           # Output: apple banana orange grape

Variable Management Commands

Viewing variables:
# List all variables
set

# List environment variables only
env
printenv

# Show specific variable
echo $PATH
printenv PATH

# Check if variable is set
declare -p VARIABLE_NAME 2>/dev/null && echo "Set" || echo "Not set"
Unsetting variables:
# Remove a variable
unset MY_VAR

# Remove from environment
unset PATH  # Be careful with this!

# Check if unset
echo ${MY_VAR:-"Variable is unset"}

Practical Examples

Script with command-line arguments:
#!/bin/bash
# script.sh - Example script using variables

SCRIPT_NAME=$0
FIRST_ARG=$1
SECOND_ARG=$2
ARG_COUNT=$#

echo "Script name: $SCRIPT_NAME"
echo "First argument: ${FIRST_ARG:-'Not provided'}"
echo "Second argument: ${SECOND_ARG:-'Not provided'}"
echo "Total arguments: $ARG_COUNT"
echo "All arguments: $@"

# Usage: ./script.sh hello world
Configuration management:
#!/bin/bash
# Configuration script

# Set default values
CONFIG_DIR=${CONFIG_DIR:-"/etc/myapp"}
LOG_LEVEL=${LOG_LEVEL:-"INFO"}
DEBUG_MODE=${DEBUG_MODE:-"false"}

# Create configuration
cat > app.conf << EOF
config_dir=$CONFIG_DIR
log_level=$LOG_LEVEL
debug_mode=$DEBUG_MODE
EOF

echo "Configuration created with:"
echo "Config Dir: $CONFIG_DIR"
echo "Log Level: $LOG_LEVEL"
echo "Debug Mode: $DEBUG_MODE"
PATH manipulation:
# Add directory to PATH
export PATH="$HOME/bin:$PATH"

# Add to end of PATH
export PATH="$PATH:/opt/custom/bin"

# Remove directory from PATH
PATH=$(echo $PATH | tr ':' '\n' | grep -v '/unwanted/path' | tr '\n' ':' | sed 's/:$//')

# Check if directory is in PATH
if [[ ":$PATH:" == *":/usr/local/bin:"* ]]; then
    echo "/usr/local/bin is in PATH"
fi

Variable Scoping

Local vs global variables:
#!/bin/bash

# Global variable
GLOBAL_VAR="I'm global"

function test_scope() {
    # Local variable (only in function)
    local LOCAL_VAR="I'm local"
    
    # Modify global variable
    GLOBAL_VAR="Modified global"
    
    echo "Inside function:"
    echo "Global: $GLOBAL_VAR"
    echo "Local: $LOCAL_VAR"
}

echo "Before function: $GLOBAL_VAR"
test_scope
echo "After function: $GLOBAL_VAR"
echo "Local outside function: ${LOCAL_VAR:-'Not accessible'}"

Best Practices

  • Use uppercase for environment variables, lowercase for local variables
  • Always quote variable expansions: "$VAR" instead of $VAR
  • Use braces for clarity: ${VAR} instead of $VAR
  • Provide default values for optional variables
  • Use local keyword for function variables
  • Validate important variables before using them
  • Use meaningful variable names
  • Document environment variables in scripts
  • Be careful when modifying system variables like PATH
  • Use readonly for constants

Common Pitfalls

  • Spaces around equals sign: VAR = value (wrong) vs VAR=value (correct)
  • Unquoted variables can cause word splitting and globbing
  • Using $* instead of $@ in most cases
  • Not checking if variables are set before using them
  • Overwriting important system variables accidentally
  • Not using local variables in functions
  • Case sensitivity issues with variable names

Advanced Techniques

Dynamic variable names:
# Create variables dynamically
for i in {1..3}; do
    declare "VAR_$i=value$i"
done

# Access dynamic variables
for i in {1..3}; do
    var_name="VAR_$i"
    echo "${!var_name}"  # Indirect expansion
done
Variable validation:
#!/bin/bash
# Validate required variables

required_vars=("DATABASE_URL" "API_KEY" "LOG_DIR")

for var in "${required_vars[@]}"; do
    if [[ -z "${!var}" ]]; then
        echo "Error: $var is not set"
        exit 1
    fi
done

echo "All required variables are set"
Related Commands: export, unset, env, set, declare