Problem
Recently at my day job I’ve been having to go through some pretty old Bash scripts that I’ve basically inherited. As I’ve been going through them I’ve been seeing a lot of confusion as to the proper use of Bash’s export command. The major offense? Not really understand whether a particular variables needs to be exported, or not. So I thought I’d take a moment just to clarify when and when not to use export.
The export command has really only one true purpose. To mark and/or unmark variables (and functions) that you want to have automatically exported to environments of subsequently executed commands. So if you create a script that calls other commands, and you want to push variables into the environment of these commands, then you’ll want to use export.
Example #1 (without export)
For example, let’s say we have the following 2 scripts:
1 2 3 4 5 6 7 | #!/bin/bash # script #1: parent.bash var1="this was set by the parent shell script" echo "inside $0 script: $var1" ./child.bash |
1 2 3 4 | #!/bin/bash # script #2: child.bash echo "inside $0 script: $var1" |
And when I run the script parent.bash I get this output:
1 2 3 4 5 | # output from parent.bash & child.bash (without export) % ./parent.bash inside ./parent.bash script: this was set by the parent shell script inside ./child.bash script: |
Notice how the variable $var1, which was set in the parent.bash script, didn’t get displayed by the child.bash script? Now watch this example with the variable $var1 exported in the parent.bash script.
Example #2 (with export)
1 2 3 4 5 6 7 | #!/bin/bash # script #1: parent.bash export var1="this was set by the parent shell script" echo "inside $0 script: $var1" ./child.bash |
1 2 3 4 | #!/bin/bash # script #2: child.bash echo "inside $0 script: $var1" |
And when we run parent.bash
1 2 3 4 5 | # output from parent.bash & child.bash (with export) % ./parent.bash inside ./parent.bash script: this was set my the parent shell script inside ./child.bash script: this was set my the parent shell script |
Example #3 (un-exporting)
Export isn’t just a one trick pony. It can also unmark a previously exported variable.
1 2 3 4 5 6 7 8 9 | #!/bin/bash # script #1: parent.bash export var1="this was set by the parent shell script" echo "inside $0 script: $var1" ./child.bash export -n var1 ./child.bash |
1 2 3 4 | #!/bin/bash # script #2: child.bash echo "inside $0 script: $var1" |
1 2 3 4 5 6 | # output from parent.bash & child.bash (with a before/after export) % ./parent.bash inside ./parent.bash script: this was set by the parent shell script inside ./child.bash script: this was set by the parent shell script inside ./child.bash script: |
Here we see the effects of the export -n on child.bash the 2nd time it’s called.
Which Variables are Flagged for Export?
You can use the command export -p to get a list of all the variables marked for export, like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | % export -p declare -x CCACHE_DIR="/var/cache/ccache" declare -x CCACHE_UMASK="002" declare -x COLORTERM="gnome-terminal" declare -x CVS_RSH="ssh" declare -x DESKTOP_SESSION="gnome" declare -x DISPLAY=":0.0" ... ... declare -x SHELL="/bin/bash" declare -x SHLVL="4" declare -x TERM="xterm" declare -x USER="root" declare -x WINDOWID="77021004" declare -x XMODIFIERS="@im=imsettings" declare -x var1="this was set by the parent shell script" |
What else?
There is one additional trick related to exporting variables, but it doesn’t make use of the export command. It uses Bash’s set command. This command allows you to automatically export ALL the variables that have been modified or created to the environment of subsequent commands.
Here’s a quick example:
1 2 3 4 5 6 7 8 9 10 11 12 | #!/bin/bash # script #1: parent.bash # automatically export EVERYTHING set -a var1="this was set by the parent shell script" var2="this was set by the parent shell too" echo "inside $0 script: $var1" echo "inside $0 script: $var2" ./child.bash |
1 2 3 4 5 | #!/bin/bash # script #2: child.bash echo "inside $0 script: $var1" echo "inside $0 script: $var2" |

Now how do you set the variables in the child shell, and access them from the parent shell? (Better question, after setting variables in child shell, how can you switch back to the parent shell without exiting/killing the child shell, so that you can then access those variables from the parent shell?) Thanks!
This isn’t possible. A child shell, also refereed to as a subshell, can not create variables which are then visible to its parent. This excerpt is from the Advanced Bash-Scripting Guide:
The full text above can be read here from the Advanced Bash-Scripting Guide’s section on subshells.
If you want a child script to set environment variables that a parent can see -do this:
We often create a low-level script that sets up environment variables and is called as a child script from several different parent scripts.
The trick – you SOURCE the script, not run it.
Example:
db_env.sh contains:
export NLS_DATE_FORMAT=’YYYY-MM-DD’;
From the parent script you do this:
. db_env.sh
echo “Date format = ${NLS_DATE_FORMAT}
The “.” says to treat the file like the .bashrc which you source and inherit it’s variables.
Yeah this isn’t really a parent/child shell scenario. What you’re doing is what would be better characterized as an include. For example:
Versus this script:
In the 2nd script both file1.sh & file2.sh would be run inside their own copies of bash, assuming they were prefixed with a shebang (#!/bin/bash). This simple fact makes the file1.sh & file2.sh child processes of the parent script’s bash, and there is no mechanism that I’m aware of within bash that allows the children to manipulate the parent’s environment variables directly. The parent could trap output that file1.sh & file2.sh might return and manipulate environment variables itself, but that’s it.