Read

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"YesYesAlmost everything: "$file", "Hi $name"
'single'No, literal textYesText with $, * or backslashes that must stay as written
noneYes, then split on spaces and globbedNoSingle 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

CommandWhat it does
name=valueAssign (no spaces around =).
echo "$name"Expand a variable, safely quoted.
${name}suffixBraces when the name touches other text.
'literal $text'Single quotes: nothing is expanded.
. file.shLoad assignments from a file into this shell.
export NAMEPass a variable to child processes.
${var:-default}Value, or `default` if empty/unset.

Quiz

  1. Which assignment is correct?

    • `count = 5`
    • `count=5`
    • `$count=5`
  2. `f="a b.txt"`. Which command opens that file?

    • `cat $f`
    • `cat "$f"`
    • `cat '$f'`
  3. What does `echo 'Total: $total'` print?

    • `Total:` followed by the variable's value
    • Exactly `Total: $total`
    • An error
  4. You want `$name` followed directly by `_backup`. Which is right?

    • `$name_backup`
    • `${name}_backup`
    • `$(name)_backup`
  5. 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

  1. 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.

  2. Create an executable script `/root/lab/l82/price.sh` that prints the literal text `Cost: $5` (with the dollar sign).

  3. `/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.