Skip to main content
Environment variables store configuration and state information that programs can access. Minishell provides commands to view, set, and remove these variables.

What Are Environment Variables?

Environment variables are key-value pairs that define the shell’s environment:
  • Configuration: Paths, preferences, locale settings
  • System Information: User name, home directory, hostname
  • Application State: Custom variables for scripts and programs
Environment variables are inherited by child processes. When you run a command, it receives a copy of the shell’s environment.

Viewing Environment Variables

Using the env Command

The env command displays all environment variables:
env
# Output:
# HOME=/home/user
# PATH=/usr/local/bin:/usr/bin:/bin
# USER=john
# SHELL=/bin/bash
# PWD=/home/user/projects
# LANG=en_US.UTF-8
# ...
Each line shows one variable in NAME=VALUE format.

Viewing Specific Variables

Use pipes to filter the output:
# Find specific variable
env | grep HOME
# Output: HOME=/home/user

# Find all PATH-related variables
env | grep PATH
# Output:
# PATH=/usr/local/bin:/usr/bin:/bin
# ...

# Check if variable exists
env | grep "^MY_VAR="

Using export Without Arguments

The export command without arguments shows all variables with the declare -x prefix:
export
# Output:
# declare -x HOME=/home/user
# declare -x PATH=/usr/local/bin:/usr/bin:/bin
# declare -x USER=john
# ...
The output is alphabetically sorted.
Both env and export (without arguments) display environment variables, but with different formatting. Use whichever format you prefer.

Setting Environment Variables

Using export

The export command creates or updates environment variables:
# Set a new variable
export MY_VAR=hello
echo $MY_VAR
# Output: hello

# Update existing variable
export PATH=/new/path:$PATH

# Set multiple variables
export VAR1=value1 VAR2=value2 VAR3=value3

Variable Naming Rules

Variable names must contain only alphabetic characters:
# Valid names
export USERNAME=john
export MYVAR=value
export APP=minishell

# Invalid names
export 123VAR=value     # Error: starts with number
export MY-VAR=value     # Error: contains hyphen
export MY_VAR=value     # Error: contains underscore
export =value           # Error: no name
Minishell enforces strict variable naming: only alphabetic characters (A-Z, a-z) are allowed. This is more restrictive than bash, which also allows underscores and digits.

Setting Empty Variables

# Set variable with no value
export EMPTY_VAR
echo "$EMPTY_VAR"
# Output: (empty string)

# Set variable to explicit empty value
export EMPTY_VAR=""
echo "$EMPTY_VAR"
# Output: (empty string)

Removing Environment Variables

Using unset

The unset command removes variables from the environment:
# Remove single variable
export MY_VAR=test
unset MY_VAR
echo $MY_VAR
# Output: (empty - variable removed)

# Remove multiple variables
export VAR1=a VAR2=b VAR3=c
unset VAR1 VAR2 VAR3

# Verify removal
env | grep "^VAR"
# Output: (no output - variables removed)

Behavior Notes

  • Removing a non-existent variable is not an error (no output)
  • The exit status is always 0
  • Once removed, the variable no longer exists in the environment
Be cautious when removing critical system variables:
unset PATH    # Commands won't be found
unset HOME    # cd without arguments will fail
unset USER    # Programs may behave unexpectedly

Variable Expansion

Access variable values using the $ prefix:

Basic Expansion

# Expand in echo
export NAME=John
echo $NAME
# Output: John

echo "Hello, $NAME!"
# Output: Hello, John!

Expansion in Commands

# Use in paths
export MYDIR=/home/user/docs
cd $MYDIR
pwd
# Output: /home/user/docs

# Use in arguments
export FILE=document.txt
cat $FILE

Quote Behavior

export VAR=hello

# Double quotes: expansion occurs
echo "$VAR world"
# Output: hello world

# Single quotes: no expansion
echo '$VAR world'
# Output: $VAR world

# No quotes: expansion occurs
echo $VAR world
# Output: hello world
Variable expansion happens inside double quotes but not inside single quotes. This lets you control when variables are expanded.

Special Variables

Minishell supports several special variables:

Exit Status ($?)

Stores the exit code of the last executed command:
# Successful command
echo "Hello"
echo $?
# Output: 0

# Failed command
ls /nonexistent
echo $?
# Output: 1

# Command not found
nonexistent_command
echo $?
# Output: 127

Shell Process ID ($$)

Returns the process ID of the current shell:
echo $$
# Output: 12345 (actual PID varies)

# Use in temporary files
echo "data" > /tmp/file_$$.txt
ls /tmp/file_*.txt

Shell Name ($0)

Returns the name of the shell:
echo $0
# Output: Minishell
These special variables are automatically maintained by Minishell and update after each command execution.

Common Environment Variables

Several variables are standard in Unix-like systems:

PATH

Defines where the shell looks for executable commands:
echo $PATH
# Output: /usr/local/bin:/usr/bin:/bin

# Add directory to PATH
export PATH=$HOME/bin:$PATH

# Remove directory from PATH (careful!)
export PATH=/usr/bin:/bin
If you unset or empty PATH, the shell won’t find commands:
unset PATH
ls
# Output: ls : command not found
You’ll need to use full paths: /bin/ls

HOME

User’s home directory:
echo $HOME
# Output: /home/user

# cd uses HOME when called without arguments
cd
pwd
# Output: /home/user

# Use in paths
cat $HOME/documents/file.txt

USER

Current username:
echo $USER
# Output: john

# Use in messages
echo "Welcome, $USER!"
# Output: Welcome, john!

PWD

Present working directory:
echo $PWD
# Output: /home/user/projects/minishell

# Changes when you cd
cd /tmp
echo $PWD
# Output: /tmp

SHELL

Path to the current shell:
echo $SHELL
# Output: /bin/bash (inherited from parent shell)

Practical Examples

Application Configuration

# Set application variables
export APP_NAME=myapp
export APP_VERSION=1.0
export APP_CONFIG=/etc/myapp/config.ini

# Use in commands
echo "Starting $APP_NAME version $APP_VERSION"
cat $APP_CONFIG

Development Environment

# Set up development paths
export PROJECT_ROOT=/home/user/projects/minishell
export SRC_DIR=$PROJECT_ROOT/src
export BUILD_DIR=$PROJECT_ROOT/build

# Navigate easily
cd $SRC_DIR
ls

Customizing Behavior

# Set editor preference
export EDITOR=vim

# Set language
export LANG=en_US.UTF-8

# Set timezone
export TZ=America/New_York

Building PATH

# Add multiple directories
export PATH=$HOME/bin:$HOME/.local/bin:/usr/local/bin:$PATH

# Verify
echo $PATH | tr ':' '\n'
# Output (each on separate line):
# /home/user/bin
# /home/user/.local/bin
# /usr/local/bin
# ...

Environment Variable Scope

Inheritance

Child processes inherit the environment:
# Set variable in shell
export MY_VAR=hello

# Run command - it sees MY_VAR
env | grep MY_VAR
# Output: MY_VAR=hello

# Shell script can access it
echo "echo \$MY_VAR" > test.sh
bash test.sh
# Output: hello

No Reverse Inheritance

Changes in child processes don’t affect the parent:
# Set variable
export VAR=original

# Run subshell that changes it
bash -c "export VAR=changed; echo $VAR"
# Output: changed

# Original shell still has original value
echo $VAR
# Output: original
This is why cd and export must be built-in commands: external commands run in child processes and can’t modify the parent shell’s state.

Troubleshooting

Variable Not Expanding

# Problem: using single quotes
echo '$HOME'
# Output: $HOME

# Solution: use double quotes or no quotes
echo "$HOME"
echo $HOME
# Output: /home/user

Variable Not Found

# Variable doesn't exist
echo $NONEXISTENT
# Output: (empty)

# Check if variable is set
env | grep NONEXISTENT
# Output: (no output)

# Set it first
export NONEXISTENT=value
echo $NONEXISTENT
# Output: value

Command Not Found After PATH Change

# Broke PATH
export PATH=/wrong/path
ls
# Output: ls : command not found

# Fix by restoring PATH
export PATH=/usr/local/bin:/usr/bin:/bin
ls
# Works now

Implementation Details

For developers interested in the internals:
  • Environment storage: Linked list structure (t_prompt)
  • Variable expansion: env_parsed.c:107-131 (vars())
  • Special variable handling: env_parsed2.c:43-61 (ft_asign_rare_value())
  • Exit status tracking: Global variable g_status
  • Variable name validation: builtins_utils.c:79-105 (check_env_name())
  • Value assignment: builtins_utils.c:107-134 (asign_env_value())
  • Variable removal: builtins.c:15-53 (remove_env(), unset())

Build docs developers (and LLMs) love