Environment variables are actually just a simple dictionary passed down from parent to child processes.
Let’s see this in action. Imagine you have a script that needs to know a specific path to a configuration file. Instead of hardcoding it, you can use an environment variable.
# Create a dummy config file
touch my_app.conf
# Set an environment variable in the current shell
MY_APP_CONFIG_PATH=/home/user/my_app.conf
# Create a script that reads the variable
echo 'echo "Using config file: $MY_APP_CONFIG_PATH"' > read_config.sh
chmod +x read_config.sh
# Run the script
./read_config.sh
Output:
Using config file: /home/user/my_app.conf
Now, if you create a child process, like another shell, and try to access it there:
# Start a new shell
bash
# Inside the new shell, try to access the variable
echo "From child shell: $MY_APP_CONFIG_PATH"
Output:
From child shell:
See? It’s gone. That’s because MY_APP_CONFIG_PATH was only set in the parent shell. It wasn’t exported.
The export command is what makes an environment variable available to child processes. When you export a variable, you’re essentially telling the operating system, "Hey, any new programs launched from this shell should inherit this variable."
Here’s how you export:
# Set and export in one go
export MY_APP_CONFIG_PATH=/home/user/my_app.conf
# Now, create a child shell again
bash
# Inside the new shell, try to access the variable
echo "From child shell after export: $MY_APP_CONFIG_PATH"
Output:
From child shell after export: /home/user/my_app.conf
This inheritance is fundamental. It’s how programs like your shell, your text editor, or any command-line tool can receive configuration or context from their parent environment without needing to be explicitly told every single time. Think of it as a way for a parent to pass notes to its children.
Managing these variables involves understanding where they live and how they’re set.
-
Shell-specific variables: These are temporary and only exist for the current shell session. Setting them directly, like
MY_VAR=value, orexport MY_VAR=value, only affects that shell and its direct descendants. They disappear when you close the terminal. -
User-specific persistent variables: To make variables available every time you log in, you typically add
exportcommands to your shell’s configuration files. For Bash, this is usually~/.bashrcfor interactive non-login shells, or~/.bash_profile(or~/.profile) for login shells.- Diagnosis: To see if a variable is set, use
echo $VARIABLE_NAME. To see all exported variables, useenvorprintenv. - Fix: Edit
~/.bashrcor~/.bash_profile. Add lines likeexport MY_PERMANENT_VAR="/path/to/config"at the end of the file. - Why it works: These files are sourced (executed) automatically when a new shell session starts, ensuring your variables are set and exported before you even type a command.
- Diagnosis: To see if a variable is set, use
-
System-wide persistent variables: For variables that should be available to all users and all processes on the system, you can place
exportcommands in files within the/etc/profile.d/directory. These files are typically executed by/etc/profileduring system startup or user login.- Diagnosis: Same as above (
echo $VARIABLE_NAME,env,printenv). - Fix: Create a new file, e.g.,
/etc/profile.d/my_custom_vars.sh, and addexport MY_SYSTEM_VAR="some_global_setting". Ensure the file has execute permissions (chmod +x /etc/profile.d/my_custom_vars.sh). - Why it works: Files in
/etc/profile.d/are designed to be modular additions to the system’s global environment setup.
- Diagnosis: Same as above (
-
Precedence: If a variable is set in multiple places (e.g., in
~/.bashrcand/etc/profile.d/), the one set later or in a more specific context (like a direct shell command) usually overrides the earlier or more general one.
The export command isn’t just for strings. It works for any value you assign. For instance, export MY_PORT=8080 makes the number 8080 available to child processes. The receiving process then reads it as a string and must parse it if it expects a number.
Most people think of environment variables as simple key-value pairs for configuration. What’s less obvious is how deeply they are integrated into the Unix process model. When a process forks and execs a new program, the entire environment of the parent is copied to the child, and export is the mechanism that flags which of those variables are part of that copy. It’s a core part of how the operating system manages process context and allows for dynamic configuration.
Once you’ve got persistent variables set up, you’ll want to understand how to make sure they are correctly loaded by different types of shells and applications.