When it comes to shell scripting, although I’ve developed on UNIX-like systems for years and there’s even been times when my primary task was writing shell scripts, I seem to only ever retain a level of understanding that “gets the job done”.
One quickly forgotten topic is the scoping behaviour of shell and environment variables. So I thought I’d refresh my knowledge and write about it.
Simple shell variables
First, some basics.
In the Bash shell (sh/bash), you define variables by declaring a key-value pair:
This gives you a shell variable,
VAR1, whose value you can see with
echo command, referencing the variable using the
You can use single quotes to handle significant spaces and to express reserved symbols. Single quotes provide strong quoting - everything is interpreted as a string.
Similary, you can use double quotes to handle significant spaces but also to perform variable expansion and command substitution. Double quotes provide weak quoting.
This quoting behaviour applies generally to Bash.
The variable scope is characterised by the processes in which they are visible.
Processes are arranged in a tree structure with parent and child relationships between them: a process that starts another is the parent, and the newly created one is the child or sub-process.
Consequently variables are classified into two categories:
- Shell variables
- Environment variables
Shell variables are only visible to the current shell whereas environment variables are also visible to sub-processes of the shell.
Exporting shell variables to make environment variables
Previously section, we were defining shell variables which, by their nature, are only visible inside the current shell.
In Bash, you use the
export command to make a shell variable available to child processes - i.e. to make it an environment variable.
Let’s define a little script:
print_env.sh with execute permissions.
Running a script starts a child process which inherits its environment variables from the variables exported by the parent shell.
So if we don’t export the variable
VAR1, then the child process won’t see it.
Case in point:
VAR1 isn’t defined in the script’s shell.
So let’s make
VAR1 visible by exporting it from the original shell and then rerunning the script:
Typically the definition and exporting are combined into the one command:
Some important caveats:
- The value received by the child is a copy of the parent’s variable taken at the time when the child process starts.
- You can’t modify the enviroment of a parent shell.
Unsetting and demoting
You can use the
unset command to delete a variable.
If you no longer want to export a variable, but still keep it defined in the current shell use
Working with environment files
You can define an environment by adding the variable definitions to a file and using the
source command to apply it.
source is a Bash shell built-in command that executes the content of the file passed as argument, in the current shell. The file can set shell variables and environment variables.
Let’s create a file,
Then initialise our current shell via
If we’d instead put these variable definitions into an executable script and run it, then it would have initiated its own short-lived environment, rather than our current shell.
If you want to run a script with a specific environment without affecting the current shell, then use the
env command to supply a short-lived environment to a process.
That’s it for now. I hope you find these notes helpful!
This post is Creative Commons Attribution 4.0 International (CC BY 4.0) licensed.