Table of Contents
Understanding Variables in Shell Scripts
In shell scripting, variables give you a way to store values and reuse them. They are one of the most important tools for making scripts flexible instead of hard coding every value.
This chapter focuses on variables in simple shell scripts, mostly with bash. Other shells may add features, but the core ideas stay the same.
Creating and Using Variables
In shell scripts, a variable is created when you assign a value to a name. There is no separate declaration step and there is no data type in the strict sense. Everything is stored as text.
You assign a value like this.
name="Alice"
greeting="Hello"
number=42
pi="3.14"
There are two key rules here. First, do not use spaces around the = sign. Second, a variable name usually uses letters, numbers, and underscores, and it must not start with a number. Names such as USER_NAME, file1, or temp_value are fine. Names such as 1name are not.
To use the value stored in a variable, you add a dollar sign in front of its name.
echo "$greeting, $name"
echo "The number is $number"
Here, "$greeting, $name" is expanded by the shell before echo runs. The shell replaces $greeting with Hello and $name with Alice.
Always remember:
name=value to set a variable, with no spaces around =.
$name to read the value of a variable.
Quoting and Variable Expansion
Quoting controls how the shell interprets special characters such as spaces or the dollar sign. This has a direct effect on variables.
If you use double quotes, variables are expanded inside the quotes.
name="Alice Wonderland"
echo "User: $name"
This prints User: Alice Wonderland. The double quotes protect the space, so the shell passes one argument, not two.
If you use single quotes, variables are not expanded inside the quotes.
name="Alice"
echo 'User: $name'
This prints User: $name literally, because the shell treats everything between single quotes as plain text.
If you use no quotes and the value contains spaces or other special characters, the shell may split the text into several parts or interpret characters in unwanted ways. Beginners often see surprising behavior here. To keep simple scripts predictable, it is safer to wrap variable expansions in double quotes when the value can contain spaces.
Important pattern.
Use "${var}" or "$var" most of the time when expanding variables, especially when values may contain spaces.
Variable Names and Conventions
The shell is case sensitive. The variables name, Name, and NAME are all different. By convention, user defined variables in simple scripts often use lowercase or mixed case, while environment variables are usually all uppercase.
For clarity, you might use patterns such as these.
username="alice"
file_count=10
BACKUP_DIR="/backups"You can also use the value of one variable when setting another.
greeting="Hello"
name="Bob"
message="$greeting, $name"
echo "$message"
The shell evaluates the right side and then stores the resulting text in message.
If you want to clearly separate a variable name from following letters, you can add braces.
name="Bob"
echo "Hello ${name}s friend"
Here the braces tell the shell that the variable name is name, not names.
Reading Variables from User Input
Scripts become interactive when they read values from the user. The read command stores input into variables.
echo "What is your name?"
read name
echo "Hello, $name"
The command read name waits for the user to type a line and press Enter. The shell then puts that text into the variable name.
You can read multiple values at once.
echo "Enter your first and last name:"
read first last
echo "First: $first"
echo "Last: $last"
Here the shell splits the line on whitespace and assigns pieces to first and last.
You can also add a prompt directly in the read command with the -p option when using bash.
read -p "Enter your age: " age
echo "You are $age years old."Command Substitution
Sometimes you want a variable to hold the output of a command. This is common when you need a timestamp, a filename, or some system information.
You can do this with command substitution. The shell runs the command and replaces the whole substitution with the output.
There are two main forms. The modern and recommended form uses $(...).
today=$(date)
echo "Today is: $today"
Here, $(date) is replaced by the output of date. You can use this with more complex commands.
files=$(ls)
echo "Files here:"
echo "$files"The older form uses backticks.
today=`date`
The backtick form is harder to read when commands are nested, so $(...) is usually preferred.
Command substitution removes the trailing newline at the end of command output. If there are several lines, they are kept. The result is still text stored in a variable.
Local Variables and Environment Variables
Not all variables behave the same way. Some variables exist only in the current shell. Others are passed down to child processes, such as commands that your script runs.
Variables you assign simply with name=value are shell variables. They exist only in that shell session or script. When the shell runs a program, those variables are not automatically visible to that program.
Environment variables are special. They are shared with child processes. They are often written in uppercase, for example PATH, HOME, or LANG. To turn a shell variable into an environment variable, you use the export command.
name="Alice"
export name
After export name, any program started from this shell can read name from its environment.
You can also assign and export in one step.
export EDITOR=nano
How to use and manage environment variables more broadly belongs to another chapter. Here, it is enough to understand that export marks a variable to be inherited by child processes.
Variable Scope Inside Scripts
When you run a script as ./script.sh and the file has an interpreter line such as #!/bin/bash, it runs in its own shell process. Variables created inside that script are not visible in the shell that started it.
If you want a script to change variables in your current shell, you do not run it as a separate program. Instead you source it.
. ./setvars.shor
source ./setvars.shSourcing runs the commands in the current shell process, so any variable assignments affect your current shell. This is how many configuration scripts work.
Inside larger scripts you can use functions, and then variables can be declared local to those functions. That topic is covered when functions are introduced. For now, you can think of variables in a simple script as global within that script, unless you deliberately use more advanced features.
Default Values and Parameter Expansion
The shell has a feature called parameter expansion, which lets you handle missing or empty variables in a compact way. You use a slightly extended syntax around variable names.
One common form provides a default value if a variable is unset or empty.
echo "Username: ${USER:-unknown}"
If USER has a value, the shell uses it. If USER is unset or empty, the shell uses unknown instead. The pattern is:
$$
\texttt{\${var:-default}}
$$
which you can read as "use var if set and not empty, otherwise use default."
There is also a form that not only uses a default value for that expansion, but also assigns it to the variable if it was missing.
echo "Starting with PORT=${PORT:=8080}"
If PORT was unset or empty, this expansion sets PORT to 8080 and expands to 8080. If PORT already had a value, it stays unchanged and that value is used.
The pattern here is:
$$
\texttt{\${var:=default}}
$$
That is, "if var is unset or empty, set it to default and use that."
These forms are very useful for building scripts that can accept environment variables or command line options, but also behave sensibly when no values are provided.
Useful parameter expansion patterns.
"${var:-default}" uses default only for that expansion.
"${var:=default}" also assigns default to var if it was empty or unset.
Arithmetic with Variables
While the shell mostly treats variables as text, you can still perform simple integer arithmetic using special syntax. This is enough for basic counters or simple calculations.
The most common form uses double parentheses.
x=5
y=3
sum=$(( x + y ))
echo "$sum"
Inside $(( ... )) you can write expressions with integer operators such as +, -, *, /, and % for remainder. The shell evaluates the expression and returns the result as text.
You can also update a variable in place.
count=0
count=$(( count + 1 ))
echo "$count"
For bash, there is also a shortcut.
(( count++ ))
This increments count by 1. The (( ... )) form is discussed more in the chapter about conditionals and control structures, but here you can see it as a simple arithmetic tool.
Remember that shell arithmetic works with integers only. If you try to use non integer values such as 3.14, they are not handled as floating point numbers. For more complex math, scripts usually call external tools.
Common Pitfalls with Variables
Several mistakes occur frequently when beginners start using variables in shell scripts. Recognizing them early saves debugging time.
A very common error is placing spaces around = during assignment.
name = "Alice" # Incorrect
This does not assign to name. The shell reads name as a command and = and "Alice" as its arguments. To assign, you must write:
name="Alice" # CorrectAnother common issue is forgetting the dollar sign when reading a variable.
name="Bob"
echo "Hello, name" # Prints literally 'name'
echo "Hello, $name" # Prints the value
You must use $name or ${name} to expand the variable.
Not quoting variables is a more subtle problem. If a variable contains spaces, the shell will split it into multiple arguments unless you wrap it in double quotes.
file="My Document.txt"
rm $file # Dangerous. Treated as 'My' and 'Document.txt'
rm "$file" # Safe. One argument
To reduce surprises, get used to writing "$var" when you use variables in commands, particularly when dealing with filenames or input from users.
Finally, remember that variables in a script do not affect your interactive shell when the script is executed normally. If you run:
#!/bin/bash
NAME="Alice"
and then execute ./script.sh, the variable NAME will not exist in your shell afterward. That script had its own shell process. To bring variables into your current shell, you must source the script.
Summary
Variables give shell scripts memory. You store text values with name=value, always without spaces. You read them with $name, usually wrapped in double quotes to keep spaces safe. You can accept user input with read, capture command output with $(...), and adjust behavior with parameter expansion such as ${var:-default}. Arithmetic expansion with $(( ... )) lets you perform simple calculations on integer values.
These tools prepare you for writing scripts that respond to different inputs and contexts, which you will build on in later chapters when you add conditionals, loops, and functions.