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" |