bash variables
src: Understanding Bash Variables - Earthly Blog - 2021-11-03
Abstract
List the usage of bash variables for different contexts.
- you can see the defined variables in the your current shell session with
set
command- local variables can be defined by setting directly the
variable_name="variable value"
and can be read using$
, e.g.echo $variable_name
- variables in single quotes are not substituded
- bash arrays can be defined by using their index directly, like
numbers[0]=0
ormore_numbers=(3 4)
- bash arrays can be read using the index, e.g.
${numbers[0]}
or${numbers[@]}
for all items- you can unset a variable using
unset
instruction$1
contains the first argument’s value of a shell script$#
is the number of arguments$@
is the array of arguments$?
will contain the exit code- to manipulate the arguments, you can use
for arg in "$@"; do echo $arg; done
- you can also pass variables by prepending, e.g.
variable_name=foo ./prepend.sh
- you can export a variable with
export VAR=foobar
to share with new bash processes.bashrc
is a bash script that is run whenever a new shell session starts
Bash is not just a UNIX shell, it’s also a programming language. And like most programming languages, it has variables. You use these shell variables whenever you append to your PATH
or refer to $HOME
or set JAVA_HOME
.
So let me walk you through how variables work in bash, starting with local shell variables and then covering special and environment variables. I think you’ll find understanding the basics to be extremely helpful.
First, let’s take a look at all the currently defined variables in your current shell session. You can see this at any time by running set
.
Local Shell Variables
Local shell variables are local to the current shell session process and do not get carried to any sub-process the shell may start. That is, in Bash I can export variables and variables I don’t export are called local. This distinction will make more sense once we get to exporting.
For now, though, let’s look at some examples.
You can define shell variables like this:
And access them by using a dollar sign ($
):
You can also refer to them within double-quoted strings:
Use single quotes when you don’t want variable substitution to happen:
Bash Arrays
Bash also has arrays. You can define them like this:
Or like this:
And access them like this:
Output
zero: 0
one: 1
two: 2
$numbers: 0 1 2
three: 3
four: 4
$moreNumbers: 3 4
Bash v4 also introduced associative arrays. I won’t cover them here but they are powerful and little used feature (little used since even the newest versions of macOS only include bash 3.2).
Running Shell Scripts
You can declare bash variables interactively in a bash shell session or in a bash script. I will put a shebang at the top of the scripts (#!/bin/bash
).
To run these, save the code in a file:
Then make the file executable:
Then run it:
Often I’m going to skip these steps and just show the output:
Output
This is a bash script bash.sh
This makes the examples more concise but if you need clarification, or would like to learn more about shebangs, check out Earthly’s understanding Bash tutorial.
You can use unset
to unset a variable. This is nearly equivalent to setting it to a blank value, but unset will also remove it from the set
list.
Bash Special Variables
Bash has built-in shell variables that are automatically set to specific values. I end up reaching for these primarily inside shell scripts. First up is the built-ins for accessing command-line arguments.
Bash Command Line Arguments
When writing a shell script that will take arguments, $1
will contain the first argument’s value.
cli1.sh
Arguments continue from there to $9
:
cli2.sh
For arguments above nine, you need to use ${}
to delimit them. Otherwise, you get an unforeseen result:
cli3.sh
I am getting 15
for $15
because bash expands it as the first parameter ($1
) followed by the literal number five (5
).
You can also access an array of command-line arguments using the built-in $@
and the number of arguments using $#
.
args.sh
You manipulate that array of command line arguments using a for loop.
args.sh
Passing Variables as Arguments in Bash
If you need to send in arguments that contain spaces, you want to use quotes (double or single).
Command-line arguments follow the same rules as local variables, so I can use double quotes when I want to expand a variable inside of the string or single quotes when I don’t want to.
Prepending a Variable in Bash
Another way you can pass variables to a subshell is by including the definition before the call to your executable:
prepend.sh
To prepend.sh
these look like global environmental variables, which we will be covering next. But in fact, they are only scoped to the specific process this is running this script.
Exit Codes
Where programs finish executing they can pass an exit code to the parent process which can be read using $?
:
A return code of zero indicates success and if you don’t indicate otherwise, zero is returned by default.
You can assign this exit status a variable use it later.
Environmental Variables
Environmental variables work exactly like other variables except for their scope. By convention, environmental variables are named all in upper-case. You list them with env
and view the value of specific vars using printenv
.
You can use them directly in the terminal:
And just like local shell variables, you can change their value:
And use them in a bash scripts:
args.sh
Output
PWD: /
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Bash Export Variable
The local variables I started with never leave the current shell process. If I declare a variable and then start a new bash process, it won’t be set.
You can pass these variables in one by one using the prepend syntax i showed earlier (name="name" bash -c 'echo $name'
) but there is another way and that is using export
.
When I use export
to define a variable, I’m telling bash to pass it along to any child process created, thus creating a global environmental variable.
This is a one-way street, though. Exporting from a child process does not make the shell variable accessible to the parent.
Also, these variables are not persistent. If I start a new shell session, the variables I exported in a previous session won’t be present. To get that behavior, I need to export them from my .bashrc
.
.bashrc
.bashrc
is a bash script found at ~/.bashrc
. It runs whenever a new interactive bash shell starts. So, by adding an export there, I am ensuring that it will present in all shell sessions started after that point. I have to start a new shell session or source ~/.bashrc
to see this change, though.
(Using .bashrc
is how you can configure your bash prompt, using the variable $PS1
, and many other things, but that is a topic for a different article.)
Conclusion
Those are the basics of bash shell variables. There is much that I haven’t covered, but this is the basics. I hope this overview gave you enough depth to understand most use-cases you encounter in your day-to-day work.
Also, if you’re the type of person who’s not afraid to solve problems in bash, then take a look at Earthly. It’s a excellent tool for creating repeatable builds in an approachable syntax.