Frequently Asked Question

Why must I quote my variables, and what is word splitting?

When bash expands $file, it does not simply paste the value into the command. By default it then performs word splitting, chopping the result into multiple words at any whitespace, and pathname expansion (globbing), turning anything that looks like a wildcard into a list of matching files. So if file="my report.txt", the command rm $file becomes rm my report.txt, two arguments, and removes (or tries to remove) two non-existent files. If file="*", rm $file becomes rm followed by every entry in the current directory, a catastrophic outcome.

Wrapping the variable in double quotes, rm "$file", suppresses both behaviours: the expansion stays as a single argument, with whitespace and wildcards intact. The rule of thumb is to quote every variable expansion in every command, every time, except in a few narrow cases where you deliberately want splitting (assigning an array from a command's output, or passing flags from a variable). ShellCheck flags unquoted expansions as SC2086 and is right virtually every time.

Further reading and video