How to Set Environment Variables in Linux

How to Set Environment Variables in Linux

A value you set in one terminal may be missing when you open another. Environment variables are name-value pairs that processes receive when they start.

In this piece, I’ll show how Bash passes a value to child commands and how to choose a startup file for a later session.

TL;DR

Use export in Bash to pass a variable to child commands, or choose a startup file when later sessions need it.

  • For one command, put NAME=value before the command.
  • For this shell and its children, use export NAME=value.
  • For a new login or service, set the value in the configuration that starts that process.

What Are Environment Variables in Linux?

An environment variable is a name-value pair a process receives when it starts.

CommandWhat it showsScope
printenv NAMEOne exported valueEnvironment passed to the command
envEnvironment available to a processEnvironment passed to the command
setBash parameters and functionsCurrent shell, including unexported parameters

Use printenv to check one exported value because it shows exactly what the command’s environment contains. The Bash set builtin includes unexported parameters, so it can show shell state that printenv omits.

How to Set Environment Variables in Linux

The next command shows how Bash passes an exported value to child commands.

Step 1: Set a value for this shell or one command

Save this short script as session-variable-demo.sh, then run bash session-variable-demo.sh. It sets APP_MODE for child commands and then overrides it for one command.

#!/usr/bin/env bash
set -eu
export APP_MODE=development
printf 'Shell value: %s\n' "$APP_MODE"
printf 'Child process value: '
sh -c 'printf "%s\\n" "$APP_MODE"'
printf 'One-command value: '
APP_MODE=preview sh -c 'printf "%s\\n" "$APP_MODE"'
printf 'Parent after one-command value: %s\n' "$APP_MODE"

The captured output is:

Shell value: development
Child process value: development
One-command value: preview
Parent after one-command value: development
Terminal output showing an exported Bash variable and one-command variable scope
The child receives development, the one-command child receives preview, and the shell keeps development.

I ran the script and saw the child receive development, while the one-command override returned preview.

Step 2: Load a value in a new Bash login

Add export APP_MODE=development to ~/.profile for a Bash login that reads that file. Run bash profile-variable-demo.sh from the directory holding the script to test it with a temporary home.

#!/usr/bin/env bash
set -eu
demo_home="$PWD/.env-demo/home"
mkdir -p "$demo_home"
printf '%s\n' 'export APP_MODE=development' > "$demo_home/.profile"
printf 'Login-shell value: '
env -i HOME="$demo_home" PATH=/usr/bin:/bin bash --login -c 'printenv APP_MODE'

The captured output is:

Login-shell value: development
Terminal output showing Bash reading APP_MODE from a temporary login profile
A fresh Bash login prints the APP_MODE value set in the temporary profile.

I saved the profile in a test home, and a fresh login printed development from it.

Which File Should You Use, and How Do You Fix a Missing Variable?

Choose a configuration read by the process that launches the target, because shell and service startup contexts differ.

TargetConfiguration to considerBoundary
Interactive non-login Bash~/.bashrcRead when that kind of Bash starts
Bash login session/etc/profile if present, then ~/.bash_profile, ~/.bash_login, or ~/.profileReads the first available personal file
Login environment through PAM/etc/environmentAssignment lines only
systemd user service~/.config/environment.d/*.confApplies to services started by the user manager
System serviceThe unit’s Environment= or EnvironmentFile= settingSet this on the service unit

Bash checks its login files in order, so use the first file present in the user’s home directory.

Write NAME=value in /etc/environment because PAM treats this file as assignments rather than a Bash script.

Use the service’s documented credential mechanism for passwords or key material. The systemd.exec(5) manual explains why environment variables are unsuitable for service secrets.

Match the symptom to the closest cause in the table before changing configuration.

SymptomCause to checkFix
printenv omits a valueThe parameter stayed local to the shellUse export NAME=value
A new terminal lacks the valueThe assignment was only in the old shellAdd it to the startup file that new shell reads
A GUI app or service lacks itIt starts outside that shell’s child process treeConfigure its desktop or service manager
A command disappears after changing PATHThe assignment replaced existing search directoriesPreserve the old value when adding a directory
A setting returns after unsetA startup or service file defines it againRemove the source assignment, then start the target again

When adding a personal executable directory, prepend it without discarding the existing PATH:

export PATH="$HOME/bin${PATH:+:$PATH}"

This puts the new directory ahead of existing entries, so a matching executable there takes priority. Check that the directory exists and is trusted before adding it to PATH. For a command that still cannot be found, see the Linux command-not-found troubleshooting guide.

To remove a value from the current Bash session, use unset NAME. If it comes back in a new session, remove its assignment from the startup or service configuration that supplies it. A Java program may need its own JAVA_HOME value, covered in the Linux JAVA_HOME guide.

Common Errors with nohup

nohup keeps a command running after a hangup signal. Put the variable in the launch command when that process needs it.

ProblemWhat to checkAction
The background command lacks a valueThe variable was assigned but not exportedUse NAME=value nohup command or export NAME=value first
The value is missing in another terminalThat terminal is a separate process treeSet it in the startup configuration for that login
The command runs but cannot find an executablePATH was replaced instead of extendedPreserve the existing PATH when adding a directory

Use NAME=value nohup command because the assignment applies to that invocation. Configure a service or later login through its own launch settings.

Conclusion: Match a Variable to Its Scope

Before restarting a background job, check its command and the output file it writes.

FAQ

These answers cover scope questions that come up after setting a value.

Why does export not survive a new terminal?

export changes the current shell and the environment it passes to child processes. A new terminal is started separately, so add the assignment to the startup file that shell reads.

Can env change the calling shell?

No. env NAME=value command runs the command with a modified environment. It does not change the environment of the shell that launched it.

Does Bash always read ~/.profile?

No. A login Bash reads the first available file among ~/.bash_profile, ~/.bash_login and ~/.profile. An interactive non-login Bash reads ~/.bashrc.

How do I set a variable for a systemd user service?

Place a KEY=value assignment in a .conf file under ~/.config/environment.d when the program is started by the systemd user manager. It does not apply to every shell or system service.