Bash Shell

Exporting Variables in Bash; why is it done, and how can it be done well? This article will teach you about subshells, and will exemplify Bash variable exporting therewith, showing you how to export variables, and how to avoid mistakes.

Exporting Variables in Bash

When developing more complex scripts in Bash, which employ for example subshell and multi-threaded and/or background process setups, one will regularly have to pass variables from the master shell to a subshell. It is exactly in these types of situations that exporting shell variables becomes of interest.

What Is a Bash subshell?

A Bash subshell, or a child shell, is nothing more then a Bash command line interpreter (in other words, the Bash shell) restarted from within itself. The original process has thus become the master process, and the second process to be started (the one started inside the master, or fist, process) is going to be the subshell. If the master process/shell terminates, so will the subshell running within it.

Let’s do this very simply as follows:

echo $$
ps -ef | grep -v grep | grep your_process_id

Simple example of starting a subshell in Bash

Nothing seemed to happen when we typed bash in the terminal and pressed enter. However, what happened in the background was that a new process (the subshell) was started and we immediately entered into that subshell.

We can verify the same by checking what sort of processes are live. First, we discover the PID (process ID) of our current (sub-)shell. We can do so by inspecting the $$ variable with echo. The PID is 362827. Next, we can our process list using ps -ef and we exclude the grep process from the list with the grep -v negation in | grep -v grep.

We discover that the PPID (the parent process ID) of our subshell with PID 362827 is 362815 (first green box). The PID (the process ID of the program mentioned at the end of the line) is always displayed on the left, whereas the parent process ID (PPID) is always displayed on the right. This allows us to backtrack as far as we can or like to go.

We thus discover that the 362815 process (the main/parent process which hosts the 362827 subshell) is owned by process 13185 (white highlight), and this process is identified by the last ps as the terminal window which was started in the desktop environment. This in turn is owned by a much earlier started process 2184 (process name not shown here) etc.

The total (visible) hierarchy is thus 2184 > 13185 (terminal window) > 362815 (master/main shell inside the terminal window) > 362827 (the subshell started from within the Bash shell with process ID 362815). For a more visible representation of this hierarchy, you may like to checkout the pstree command/utility, which may require installing on your operating system.

To learn more about Unix PID’s, see What Are Unix PIDs and How Do They Work? by Anthony Heddings.

It is import to understand how the hierarchy of Bash works as it helps us understand why and where the export of variables becomes interesting, and often necessary.

Exporting Variables to Subshells

There are many ways to create a subshell. One way is to simply start a subshell as shown above by typing bash and executing further command line based commands. Another is by starting a GNU screen session (see How to Use the GNU Screen Utility in Linux if you like to learn more about GNU Screen).

You can also use the $(subshell code goes here) subshell idiom directly from within a command line and/or your Bash scripts. Finally, one can start a subshell simply by placing a process into background. To learn more about background process management, see Bash Background Process Management.

So with all of these methods to initiate subshells, how can one easily pass variables from one shell to another? Sure, one could store the variables in a file (in any format), but this will increase the number of I/O operations, and the complexity of the Bash code that handles this writing and reading of variables.

There is an easier way. You may think about it like global variables in other coding languages. Yes, perhaps global variables tend to be shunned or frowned upon, but remember we are dealing with separate processes here.

In any multi-thread/multi-process programming in any language, there would still be a supervisory module/code which would pass variables back and forth between the threads. Such variables could be considered global also.

The syntax for the export command is very simple. Simply prefix the variable assignment with the export command:

export A=1
echo ${A}
echo ${B}

Exporting of a variable

Here we start a subshell, and show how the variable A was correctly passed to the subshell by using the export command when defining it. We also see how the variable B has not transferred to the subshell, as it was defined without using export.

The export property is a specific property which can be turned on and off for a given variable. It is easily turned on by using the export command prefix when defining the variable.

Once such a property is set, it remains active. This is something to watch out for when coding as it can lead to confusing results if one does not know this operation specific. It is easy to assume one is “reusing” a variable with the same name, or even to accidentally use a similar variable name from different scripts in the subshell etc. Let’s explore an example:

export C=1
export D=
echo ${C}
echo ${D}

Shows the stability of the export property of a variable

In this example we see that the D variable retains it’s export property, even when re-assigned without the explicit export command, and it’s value is correctly passed to the subshell.

The export property can also be removed from/turned off for a variable, by using the -n option to export. However, to be effective, this has to be done from the master/main shell, and not the subshell:

export -n D
echo ${D}
echo ${D}
echo ${D}

One cannot remove the export property from a variable from within a subshell if that property was set by the master/parent shell

This example continues on from the last one (i.e. still from within the active subshell). We try and remove the export property from the D variable, and subsequently exit the subshell using exit. We see that on returning to the main shell that our D variable has retained it’s value, and that value remains retained when re-entering a new subshell. Thus, as seen, an export property cannot be removed from a variable from within a subshell if that variable was given an export property in the main/master shell.

This is alike to other Bash coding methods: the subshell cannot affect the master/main shell. This also makes the most sense from a security perspective in many cases, and security is likely the reason the Bash developers chose to implement it this way. Let’s take it one step further now and remove the export property from the main/parent shell:

export -n D
echo ${D}

The parent/master shell can remove the export property from the variable

Here we exit the subshell just created in the last example, and then unset the export property from the D variable. Next we re-enter a subshell alike to our last example, and we can see that our D variable is empty, as it was no longer exported to the subshell. You can also run export -p to see all export variables. The variables you exported are likely near the top of this list.

export -p | head -n1

Using export -p to print exported variables


Having explored subshells and their connection with exporting Bash variables, we next exemplified Bash variable exporting. We looked at various ways to export variables, as well as a method to clear the export property from variables. We also saw a gotcha which can arise if you reuse variable names. Enjoy Exporting!

Profile Photo for Roel Van de Paar Roel Van de Paar
Roel has 25 years of experience in IT & business, 9 years of leading teams, and 5 years in hiring & building teams. He worked for companies like Oracle, Volvo, Sun, Percona, Siemens, Karat, and now MariaDB in various senior, principal, lead, and managerial roles.
Read Full Bio »