Module 9 · Shell scripting basics
Variables and quoting
Store values in variables, read them back with $, and learn once and for all what single quotes, double quotes and no quotes do.
What you will learn
- Assign and expand shell variables without the classic spacing mistakes.
- Choose between single quotes, double quotes and no quotes.
- Load variables from another file with `.` and export them to child processes.
A variable is a name that holds a piece of text. In the shell everything is text: numbers, paths, lists of words. You assign with name=value and read with $name. Two rules trip everyone at first: there are no spaces around =, and you use the $ only when reading, never when assigning.
~% name=TempMV
~% echo "Welcome to $name"
Welcome to TempMV
~% name = TempMV
sh: name: not found
~% count=3
~% echo "$count files, next is $((count + 1))"
3 files, next is 4
~% echo "${name}Lab"
TempMVLab
name = TempMV fails because the shell reads name as a command and = and TempMV as its arguments. When a variable is glued to other letters, wrap the name in braces: ${name}Lab; otherwise the shell looks for a variable called nameLab. Variable names are case-sensitive, and by convention your own variables are lowercase while environment variables like HOME and PATH are uppercase.
The three kinds of quoting
| Form | `$var` expanded? | Spaces kept? | Use it for |
|---|---|---|---|
"double" | Yes | Yes | Almost everything: "$file", "Hi $name" |
'single' | No, literal text | Yes | Text with $, * or backslashes that must stay as written |
| none | Yes, then split on spaces and globbed | No | Single words you control |
The dangerous one is no quotes. After expanding $var, the shell splits the result on spaces and expands any * or ? it finds. If file="my notes.txt", then cat $file runs cat my notes.txt and complains about two missing files, while cat "$file" opens the right one. Get into the habit of writing "$var" every time; it is never wrong, and omitting it is the number one source of script bugs.
~% file="my notes.txt"
~% touch "$file"
~% cat $file
cat: can't open 'my': No such file or directory
cat: can't open 'notes.txt': No such file or directory
~% cat "$file" && echo "(empty, but it opened)"
(empty, but it opened)
~% echo 'Cost: $5 per *'
Cost: $5 per *
~% echo "Cost: \$5"
Cost: $5
Inside double quotes a backslash still escapes $, ", ` ` and \, so "\$5" prints a dollar sign. Inside single quotes nothing is special, not even a backslash, which is why you cannot put a single quote inside single quotes; close them, add \', and reopen: 'it'\''s'`.
Variables in files, and exporting them
A file that only contains assignments is a configuration file. Load it into a script with the dot command: . /root/lab/l82/config.sh. The lines run in the current shell, so the variables are now yours. A plain variable is private to the shell that set it; to let child processes (commands you run) see it, export it, as lesson 69 showed. Scripts receive the exported environment of the shell that started them, which is how $HOME and $PATH are already there when a script begins.
Commands in this lesson
| Command | What it does |
|---|---|
name=value | Assign (no spaces around =). |
echo "$name" | Expand a variable, safely quoted. |
${name}suffix | Braces when the name touches other text. |
'literal $text' | Single quotes: nothing is expanded. |
. file.sh | Load assignments from a file into this shell. |
export NAME | Pass a variable to child processes. |
${var:-default} | Value, or `default` if empty/unset. |
Quiz
Which assignment is correct?
- `count = 5`
- `count=5`
- `$count=5`
`f="a b.txt"`. Which command opens that file?
- `cat $f`
- `cat "$f"`
- `cat '$f'`
What does `echo 'Total: $total'` print?
- `Total:` followed by the variable's value
- Exactly `Total: $total`
- An error
You want `$name` followed directly by `_backup`. Which is right?
- `$name_backup`
- `${name}_backup`
- `$(name)_backup`
How do you make a variable visible to the commands a script runs?
- `export VAR`
- Write it in uppercase
- Put it in single quotes
Practice
Write an executable script `/root/lab/l82/greet.sh` that stores `TempMV` in a variable called `name` and prints `Welcome to TempMV` using that variable.
Create an executable script `/root/lab/l82/price.sh` that prints the literal text `Cost: $5` (with the dollar sign).
`/root/lab/l82/config.sh` defines `APP_NAME`. Write an executable script `/root/lab/l82/show.sh` that loads that file with `.` (using its absolute path) and prints `App: ` followed by the value, e.g. `App: TempMV Lab`.
Open this lesson in the app to do the tasks in a real Linux machine and have them checked.