| Tested on | RHEL 10.2 (Coughlan) |
|---|---|
| Package | bash 5.2.26-6.el10 |
| Applies to | Linux distributions with Bash installed |
| Privilege | Normal user; no root required for the examples |
| Scope | Shell variables versus exported environment variables, export, export -p, export -n, unset, env, printenv, one-command VAR=value command, env -u, env -i, PATH usage, and parent/child inheritance. Does not cover startup-file placement for persistent variables in depth. |
| Related guides | Bash shell script tutorial Shell scripting course hub |
Bash environment variables let a shell pass configuration values to programs and child shells that it starts. You can set a variable in your current session, export it for programs and child shells started later, or pass a value to a single command without changing your current shell.
External programs and child shells receive environment variables from the shell that starts them. They get their own environment when they start, so later changes inside the child do not update the parent shell.
Quick Reference
| Task | Command |
|---|---|
| Set shell variable | VAR=value |
| Export variable | export VAR=value |
| Export existing variable | export VAR |
| Print one environment variable | printenv VAR |
| List environment | env or printenv |
| List Bash exports | export -p |
| One-command variable | VAR=value command |
Run command with env |
env VAR=value command |
| Remove variable for one command | env -u VAR command |
| Keep variable but stop exporting it | export -n VAR |
| Remove variable completely | unset VAR |
| Clean environment | env -i command |
Shell Variables vs Environment Variables
A shell variable exists in the current Bash process. You create one with the assignment rules covered in Bash variables: name=value with no spaces around =.
In Bash, an exported variable is included in the environment passed to commands and child processes that Bash starts. Use the export builtin to mark a shell variable for export.
| Kind | Current shell | New child process |
|---|---|---|
| Shell variable | Yes | No |
| Exported variable | Yes | Yes |
export does not create a shared variable between processes. It tells Bash to include the name and value in the environment passed to subsequently started child processes.
Set and Export Environment Variables
You can export in one step or assign first and export the name afterward. Both forms mark a variable for child processes started later in the same shell.
Set a shell variable without exporting it:
MYVAR=helloMYVAR exists in this shell only until you export it or pass it on a single command line.
Run a child Bash to check whether MYVAR is in its environment. The examples use printf for predictable status lines — see Bash echo vs printf when you choose output commands:
bash -c 'printf "child MYVAR=%s\n" "${MYVAR:-unset}"'child MYVAR=unsetThe child reports unset because MYVAR was never exported. Mark the name for export, then run the same check again:
export MYVAR=helloAfter export, the same child check should print the stored value:
bash -c 'printf "child MYVAR=%s\n" "$MYVAR"'child MYVAR=helloYou can also assign and export in two steps:
RELEASE_TAG=v2.4.1
export RELEASE_TAGEither export pattern adds the name to the environment Bash passes to the next child you start.
How Environment Variable Inheritance Works
When Bash runs an external command or starts a child shell, that process receives an environment assembled from exported and inherited variables. The child can read those values, change its own copy, or export new names locally. Changes made in the child do not modify the parent's environment.
┌────────────────────────┐
│ Parent shell │
│ export MYAPP=prod │
│ export PATH │
└───────────┬────────────┘
│ starts child process
│ exported environment passed
▼
┌────────────────────────┐
│ Child process │
│ sees MYAPP, PATH (copy) │
│ cannot modify parent's │
│ environment │
└────────────────────────┘If you set LOG_DIR=/var/log but do not export it, subsequently started child processes do not receive LOG_DIR in their environment. The name remains a shell variable in your current Bash session only.
Bash builtins and shell functions normally run in the current shell, so they can read ordinary shell variables without export. External commands and child shells need exported variables unless you pass values specifically for that command.
List Environment Variables
env, printenv, and export -p show related information, but they are used differently.
| Command | What it shows |
|---|---|
env |
Environment as NAME=value lines; can also run a program with a modified environment |
printenv |
Environment variables only; optional filter by name |
export -p |
Bash builtin listing exported names in declare -x form |
Print selected environment variables by name:
printenv HOME PATH SHELL/root
/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
/bin/bashValues differ by host and session. HOME is your home directory, PATH lists directories Bash searches for commands, and SHELL is the login shell configured for your user.
List the full environment with env or printenv when you need every name. Sorting makes the output easier to scan because variable order is not stable:
env | sort | headCOLORTERM=truecolor
HISTCONTROL=ignoredups
HISTSIZE=1000
HOME=/root
HOSTNAME=lab-shell.example
LANG=en_US.UTF-8
LESSOPEN=||/usr/bin/lesspipe.sh %s
LOGNAME=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33
MAIL=/var/spool/mail/rootThe exact names depend on your session. Child processes receive the environment in this NAME=value form. HISTCONTROL and HISTSIZE show up in many login sessions, but they do not by themselves flush commands to ~/.bash_history—when history looks wrong on disk, troubleshoot in fix Bash history not saving commands.
List variables that Bash has marked for export:
export -p | grep '^declare -x PATH='declare -x PATH="/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"declare -x shows that PATH has the export attribute.
Pass an Environment Variable to One Command
When you place an assignment before an external command, Bash passes that value to the command only. Any existing value in your current shell remains unchanged. You do not need a separate export for that one invocation.
Run a child with a staging flag for one command:
APP_ENV=staging bash -c 'printf "APP_ENV=%s\n" "$APP_ENV"'APP_ENV=stagingCheck that your interactive shell was not changed:
printf "parent APP_ENV=%s\n" "${APP_ENV:-unset}"parent APP_ENV=unsetThe parent still has no APP_ENV. The VAR=value command form is the usual pattern for APP_ENV=staging ./deploy.sh, make, or CI wrappers when you need a temporary override.
GNU env runs a command in a modified environment. Assignments on the same line apply only to that command:
env APP_ENV=staging printenv APP_ENVstagingRemove a variable for one command with env -u:
env -u HOME printenv HOMEprintenv prints nothing when HOME is not in the environment for that run. Your interactive shell still has HOME set.
Stop Exporting or Unset a Variable
export -n removes the export attribute from a variable without deleting the value in the current shell. unset removes the variable from the current Bash session.
Mark a variable exported, then remove the export attribute:
DEMO=visible
export DEMO
export -n DEMOConfirm the parent still holds the value:
printf "parent DEMO=%s\n" "$DEMO"parent DEMO=visibleVerify that a new child process no longer receives the variable:
bash -c 'printf "child DEMO=%s\n" "${DEMO:-unset}"'child DEMO=unsetDEMO remains in the parent shell but is no longer included in the environment of new child processes. Use export -n when you want to stop exporting a variable without removing it.
Remove the variable entirely with unset:
export DEMO=visible
unset DEMOVerify that the variable is no longer set:
printf '%s\n' "${DEMO:-unset}"unsetexport -n and unset solve different problems:
| Command | Value remains in current Bash? | Passed to future children? |
|---|---|---|
export -n VAR |
Yes | No |
unset VAR |
No | No |
PATH Environment Variable
PATH is a colon-separated list of directories Bash searches when you enter a command without a path. After you change PATH, the which command confirms which executable Bash resolves for a given name. In a typical shell session, PATH is also exported so child processes can inherit it. That is why you can type ls instead of /usr/bin/ls.
Inspect the current search path:
printf '%s\n' "$PATH"/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/binPrepend a directory that is not already in PATH for the rest of the session:
export PATH="$HOME/tools/bin:$PATH"The new directory should now be the first entry in PATH:
printenv PATH | cut -d: -f1-3/root/tools/bin:/root/.local/bin:/root/binKeep the existing $PATH on the right so system directories stay reachable. Avoid replacing the whole path with one directory unless you are deliberately building a minimal environment.
Why Child Processes Cannot Change the Parent
A child receives a copy of the environment when it starts. Changing a variable inside the child updates only that process and any children it starts later. The parent keeps its own value.
Export a name in the parent and let the child overwrite its copy:
export PARENT_VAR=original
bash -c 'PARENT_VAR=changed; printf "inside child PARENT_VAR=%s\n" "$PARENT_VAR"'inside child PARENT_VAR=changedRead the parent value in the same shell session:
printf "in parent PARENT_VAR=%s\n" "$PARENT_VAR"in parent PARENT_VAR=originalThe child printed changed, but the parent still holds original. No script run as a child can export a value back into your interactive shell. A child script can instead print a value for the parent to capture, write it to a file, or load logic in the current shell with the Bash source command instead of spawning a child.
Temporary vs Persistent Environment Variables
Session exports last until you close the shell or unset the name. One-command assignments last only for that command line. Neither writes anything to disk.
To load a variable automatically in future Bash sessions, place it in the startup file read by that type of Bash session. Cron jobs, systemd services, containers, and other process managers may use their own environment configuration. See Bashrc vs bash_profile for which startup file runs on login versus interactive shells.
Their lifetimes are different:
export NAME=value— available for the current shell sessionNAME=value command— available only to that command- Startup-file export — loaded again when the relevant Bash startup file runs
Start with a Clean Environment using env -i
env -i starts with an empty environment before applying the assignments you provide on the same command line. Use it when you need to reproduce a bug without inherited session variables.
Run env with only the variables you name:
env -i APP_ENV=test /usr/bin/envAPP_ENV=testOnly APP_ENV=test appears. -i ignores the inherited environment and keeps only the variables you explicitly provide.
Common Environment Variable Problems
| Symptom | Likely cause | Fix |
|---|---|---|
| Script prints empty variable | Assigned in parent but never exported | export VAR or use VAR=value ./script.sh |
| Variable works in terminal, not in cron | Cron job does not receive the same environment as your interactive shell | Set exports in the job, a wrapper script, or the crontab line |
| Child changes value, parent unchanged | Expected process isolation | Return data with stdout, a file, or source in the same shell |
command not found after PATH edit |
Typo or removed system directories | Prepend with export PATH="$HOME/tools/bin:$PATH", do not replace the whole path |
Avoid storing sensitive values in environment variables on systems where other processes or users may be able to inspect process environments. Child processes inherit exported secrets. Use the secret-management mechanism provided by your application, service manager, container platform, or CI system when appropriate.
Summary
VAR=valuecreates a Bash variable;export VARmakes it available to subsequently started child processes.VAR=value commandsets a variable only for that command.envandprintenvinspect the environment;export -pshows Bash exports.export -n VARstops exporting while keeping the Bash variable;unset VARremoves it.- Child processes cannot change environment variables in their parent shell.
References
- Bash manual — Environment — environment inheritance and execution environment
- export builtin —
exportandexport -n - env invocation (GNU Coreutils) —
env,env -u, andenv -i - printenv invocation (GNU Coreutils) — print environment variables
Frequently Asked Questions
Does export make a variable global?
No. export marks a variable to be included in the environment of subsequently executed child processes. It does not make the variable global across unrelated processes, other login sessions, or other users. Already-running children do not pick up changes you make later in the parent shell.
Why can my script not see a variable?
The variable may exist only as a shell variable in the parent terminal and was never exported. Cron jobs, systemd units, and non-interactive scripts may receive a different environment from your interactive shell. Export the name, pass VAR=value ./script.sh, or set the value where that runner reads its environment.
Can a child script export a variable back to its parent?
No. A child receives a copy of the environment at launch. Changes and exports inside the child stay in that process tree. To affect the parent shell, run source script.sh in the same shell (which has other side effects) or return data through stdout, a file, or an explicit API.
env vs printenv vs export -p?
env lists the environment and can run a command with extra, altered, or removed variables. printenv lists or prints environment values without executing a program. export -p shows Bash variables marked with the export attribute, including an exported name that may currently have no value. env and printenv show entries in the process environment.

