Script foundations

Use variables and quoting

Store values and expand them without accidental word splitting or wildcard expansion.

10 minute lesson

~~~

Shell variables hold text. You assign with name=value — no spaces around the = — and read the value back with $name.

Two quoting rules do most of the work in shell. Double quotes preserve one argument while still expanding variables inside. Single quotes preserve literal text, with no expansion at all:

project='My Notes'
printf '%s\n' "$project"   # My Notes
printf '%s\n' '$project'   # $project

What unquoted expansion does

Here is the classic failure. Compare quoted and unquoted expansion:

project='My Notes'
printf '<%s>\n' "$project"
# <My Notes>
printf '<%s>\n' $project
# <My>
# <Notes>

The quoted command prints one value. The unquoted command passes two words: after Bash expands $project, it splits the result on spaces, tabs, and newlines before the command runs. This is word splitting. printf received two separate arguments and applied the format to each one.

Now put the same mistake next to a destructive command:

file='old notes.txt'
rm $file
# rm: cannot remove 'old': No such file or directory
# rm: cannot remove 'notes.txt': No such file or directory

rm was asked to delete two files named old and notes.txt. If a file named old had existed, it would be gone now. rm "$file" removes exactly the one file you meant.

Wildcards expand too

Word splitting is not the only surprise. After splitting, Bash performs pathname expansion on unquoted results, so a value containing * gets matched against files in the current directory:

pattern='*'
printf '%s\n' $pattern    # prints every filename in the directory
printf '%s\n' "$pattern"  # *

A variable you thought held a harmless string just enumerated your files.

The habit to build

Quote every expansion unless you can explain why you want splitting: "$project", "$1", "$HOME/backups". Double-quoting a variable you want treated as one value is never wrong.

And never rely on filenames having no spaces, wildcard characters, or leading dashes. Someone eventually creates My Notes (final) *.txt, and unquoted scripts break exactly then. ShellCheck flags every risky unquoted expansion — we run it at the end of the course.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →