SkillByAIOpen interactive version →

Lesson 5 / 25

Quoting, Word Splitting and Globbing

Quote variables correctly to prevent word splitting and unexpected glob expansion.

The most important rule in Bash

After Bash expands an unquoted variable or command substitution, it performs word splitting (breaking the result on spaces, tabs and newlines, controlled by IFS) and pathname expansion (treating *, ? and [...] as file patterns). That is why rm $file with file="my report.txt" tries to delete two files, my and report.txt, and why a variable containing * may expand into a list of files. The fix is simple: double-quote expansions: rm "$file", cp "$src" "$dest", for f in "$@". Double quotes still allow $var, $(cmd) and $((math)) inside them but prevent splitting and globbing. Single quotes prevent all expansion: '$HOME' is the literal text $HOME. To include a single quote inside a single-quoted string, close and reopen: 'it'\''s', or use $'...' ANSI-C quoting, which also understands \n and \t. Leave expansions unquoted only when you deliberately want splitting or globbing, and then say so in a comment.

Why quotes matter

The unquoted version breaks on a file name with a space.

file="monthly report.pdf"
touch "$file"

ls -l $file      # WRONG: ls receives two arguments, "monthly" and "report.pdf"
ls -l "$file"    # right: one argument

pattern="*.log"
echo $pattern    # expands to matching files (or stays *.log if none match)
echo "$pattern"  # prints *.log literally

echo 'Single quotes keep $HOME literal'
echo "Double quotes expand $HOME"
printf '%s\n' $'Tab:\there, newline next\nline 2'

Putting words in a sealed envelope

Double quotes put the value in a sealed envelope: however many spaces or asterisks are inside, it travels as one item. Without the envelope, the shell tips the contents out and sorts them into separate piles.

Quick check: A variable holds "my file.txt". What happens with `rm $f` (unquoted)?

  • The file "my file.txt" is removed
  • rm receives two arguments, "my" and "file.txt"
  • Bash refuses to run the command
  • Nothing; quotes are optional
Answer

rm receives two arguments, "my" and "file.txt" — Unquoted expansion undergoes word splitting on the space.