Course outline

Bash / Basic: syntax, values, and control / Lesson 2

Preserve argument boundaries through quoting

Predict word splitting and filename expansion, then use literal arguments and Bash arrays instead of strings that merely resemble commands.

About 4 min readContent reviewed
On this page

Lesson goals

  • Distinguish single quotes, double quotes, and escapes.
  • Explain unquoted expansion and IFS splitting.
  • Choose deliberate glob behavior for empty matches.

Quotes control interpretation at the source

Single quotes preserve their contents literally, with no embedded single quote directly available inside the same quoted region. Double quotes permit parameter expansion, command substitution, and selected backslash behavior while preventing ordinary splitting and globbing of their results. A backslash can quote an individual character outside quotes. These are different mechanisms, not increasing strengths of the same decoration. Use single quotes for fixed literal text and double quotes for values that must expand but stay one argument. Shell quote syntax is removed before the called program receives its arguments.

Unquoted expansions can become several words

After applicable expansions, Bash splits unquoted results using IFS rules, then can apply filename expansion to the resulting fields. An empty unquoted expansion may disappear entirely, changing argument count. Setting IFS to an empty string suppresses splitting but is not a universal replacement for quoting, because globbing and empty-value behavior still need attention. Do not rely on a filename lacking spaces today. Treat each external value as data with a known number of arguments and inspect that boundary directly when debugging. A newline is not a safe universal filename separator.

bash Observe argument counts without filenames
value='red apple'
set -- $value
printf 'unquoted=%s\n' "$#"
set -- "$value"
printf 'quoted=%s first=<%s>\n' "$#" "$1"
Expected output
unquoted=2
quoted=1 first=<red apple>

The deliberately unquoted case demonstrates splitting only. The quoted case supplies one argument containing the space; no external command or filesystem content influences this result.

A wildcard is a filesystem query

Unquoted *, ?, and bracket expressions can select matching pathnames. This happens after splitting of ordinary unquoted expansions, so a value containing an asterisk can accidentally turn into many filenames. Quoting makes the asterisk data. Bash’s nullglob and failglob options alter what happens when a pattern has no match; the default normally leaves that pattern literal. Dot-prefixed entries have separate matching rules and options. Choose a policy deliberately for a file loop, and scope option changes so a helper does not unexpectedly alter its caller’s later expansion behavior.

Use arrays for a list of arguments

A scalar holds one string, not a reliable encoded argument vector. In Bash, an indexed array can preserve one element per intended argument, including empty strings and spaces. Expanding "${args[@]}" supplies those elements individually. Expanding the whole list as one joined string changes the contract, while unquoted expansion reintroduces splitting and globbing. Arrays are a Bash feature, so portable sh code needs another design, often positional parameters. Keep the command name separate from user data and avoid eval as a repair for incorrect list construction.

bash Preserve spaces, emptiness, and a literal wildcard
args=('red apple' '' '*')
printf 'count=%s\n' "${#args[@]}"
printf '<%s>\n' "${args[@]}"
Expected output
count=3
<red apple>
<>
<*>

The array contains three elements. The wildcard remains literal because each element expands through the quoted @ form; the empty element remains an argument.

Quoting and option handling are different defenses

A correctly quoted value beginning with a dash is still one argument that a program may interpret as an option. Use a documented -- separator where supported, or a path representation such as ./-name when appropriate. Never assume every utility recognizes the same option conventions. Quoting also does not validate a destination, restrict a pathname, or authenticate an input. It preserves argument boundaries so the next layer can apply its own rules. Review both the shell expansion and the called program’s interface before declaring an invocation safe or correct.

Common errors and fixes

A value becomes several arguments

Why it happens
An ordinary expansion was left unquoted.
How to fix it
Use "$value" for one value or a quoted array for a list.
Prevent it next time
Test spaces, empty values, and wildcard characters.

A literal asterisk selects files

Why it happens
Filename expansion followed unquoted data expansion.
How to fix it
Quote the value and separate intentional globs.
Prevent it next time
Treat globbing as an explicit filesystem operation.

Quoting is expected to stop option injection

Why it happens
The program still interprets a leading dash.
How to fix it
Use its documented operand separator or path form.
Prevent it next time
Review the called program as well as the shell.

Check your understanding

1. How many arguments should a three-element array with an empty middle value produce?

Show worked solution

"${items[@]}" produces three arguments, preserving the empty element. A joined scalar or unquoted expansion can change that count. Verify the contract using $# inside a receiving function rather than judging a decorative printed command line.

2. Why is "$path" insufficient when the selected utility treats -x as an option?

Show worked solution

Quoting preserves one argument but does not change the utility’s option parser. Add its documented -- when supported or use a suitable explicit pathname. Validate the path’s intended scope separately.

Key takeaways

  • Preserve values and lists using the right quoted form.
  • Choose glob and option behavior deliberately.

Official references