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())