LinuxII · Shell and Command-Line OperationsShell expansion
Quoting, expansion, and globbing
What you'll learn
- Choose between single quotes, double quotes, and no quotes correctly
- Explain the order of brace, tilde, parameter, command, arithmetic, word, and pathname expansion
- Use glob patterns to match filenames safely
- Avoid word splitting and pathname expansion pitfalls in scripts
Prerequisites
Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09
The single most common source of bugs in shell scripts is incorrect quoting. The shell does more to what you type than any other piece of software on the system, and almost none of it is visible.
Three kinds of quotes
| Quote | Meaning |
|---|---|
'single quotes' | Literal. No expansion happens inside. Every character is taken as-is. |
"double quotes" | Most expansions happen, but word splitting and pathname expansion are suppressed. |
`backticks` and $( … ) | Command substitution. The output of the inner command becomes part of the outer command. |
\ | Escape. Removes the special meaning from the next character. |
$ echo literal-USER; echo "double: $USER"; echo "escaped: $USER"literal $USER
double: root
escaped: $USERIllustrative output
The expansion order
Before bash runs a command, it expands parts of the line. The order is fixed and matters:
- Brace expansion —
a{1,2,3}bbecomesa1b a2b a3b. This happens first, before any other expansion - Tilde expansion —
~userbecomes that user's home directory - Parameter expansion —
$varand${var}are replaced by the variable's value - Command substitution —
$(cmd)and `cmd` are replaced by the command's output - Arithmetic expansion —
$((expr))is replaced by the result - Word splitting: the result of unquoted expansions is split on IFS (default: space, tab, newline). Suppressed inside double quotes.
- Pathname expansion (globbing): *, ?, and [] match filenames. Suppressed inside double quotes.
- Quote removal. The special meaning of the quotes themselves is stripped
A subtle point: word splitting and pathname expansion are the two things that double quotes suppress. Everything else (parameter, command, arithmetic) still happens inside double quotes.
Globbing
Glob patterns match filenames against the current directory:
| Pattern | Matches |
|---|---|
* | Any string, including empty (not crossing /) |
? | Any single character |
[abc] | Any character in the set |
[!abc] or [^abc] | Any character not in the set |
[a-z] | Any character in the range |
{a,b,c} | Brace expansion: literal alternatives |
$ ls /etc/*.conf 2>/dev/null | head -5; echo ---; ls /etc/host* 2>/dev/null/etc/adduser.conf
/etc/ca-certificates.conf
/etc/debian_version.conf
/etc/deluser.conf
/etc/environment.conf
---
/etc/host.conf
/etc/hostname
/etc/hosts
/etc/hosts.allow
/etc/hosts.denyIllustrative output
Word splitting in scripts
Word splitting is the silent force that breaks unquoted variable references:
$ name="Alice Smith"; echo Hello $name; echo "Hello $name"Hello Alice Smith
Hello Alice SmithIllustrative output
A safer pattern: always quote. The next lesson covers command composition, which is where word splitting becomes most dangerous.
Special variables worth knowing
| Variable | Meaning |
|---|---|
$0 | The shell’s own name (or the script’s name when sourced) |
$1 … $9 | Positional parameters |
$@ | All positional parameters, each as a separate word |
$* | All positional parameters joined by the first character of IFS |
$# | Number of positional parameters |
$? | Exit code of the last command |
$$ | PID of the current shell |
$! | PID of the last backgrounded process |
$- | Current shell option flags |
$ echo "I am $$, with $# args: $@"I am 12345, with 0 args:Illustrative output
Knowledge check
Knowledge check · 3 questions
Q1. Inside double quotes, which expansion is suppressed?
Q2. The expression 'echo $USER' is interpreted by the shell with $USER substituted before echo runs.
Q3. Which of the following shell-script patterns are safe to ship to production? Select all that apply.
Passing score: 75%. Answers are checked in this browser.