May 2013
M T W T F S S
« Apr    
 12345
6789101112
13141516171819
20212223242526
2728293031  
101

Refs

Categories

Archives

9,331slm
●5 ●38 ●132
 

[one-liner]: How to Use the Bash Shell's export Command

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"

Useful links

4 comments to [one-liner]: How to Use the Bash Shell’s export Command

  • Vernon Nemitz

    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:

      … Variables in a subshell are not visible outside the block of code in the subshell. They are not accessible to the parent process, to the shell that launched the subshell. These are, in effect, variables local to the child process. …

      The full text above can be read here from the Advanced Bash-Scripting Guide’s section on subshells.

  • Bob Mac

    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:

      1
      2
      3
      4
      5
      6
      7
      
      # script #1
      #!/bin/bash
       
      . file1.sh      # include contents 1st file
      . file2.sh      # include contents 2nd file
       
      # do some other stuff

      Versus this script:

      1
      2
      3
      4
      5
      6
      7
      
      # script #2
      #!/bin/bash
       
      file1.sh      # execute file1.sh
      file2.sh      # execute file2.sh
       
      # do some other stuff

      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.

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>