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, or export 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 export commands to your shell’s configuration files. For Bash, this is usually ~/.bashrc for 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, use env or printenv.
    • Fix: Edit ~/.bashrc or ~/.bash_profile. Add lines like export 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.
  • System-wide persistent variables: For variables that should be available to all users and all processes on the system, you can place export commands in files within the /etc/profile.d/ directory. These files are typically executed by /etc/profile during 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 add export 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.
  • Precedence: If a variable is set in multiple places (e.g., in ~/.bashrc and /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.

Want structured learning?

Take the full Linux & Systems Programming course →