# Always Quote Variables and Substitutions
## Rule
ALL variable expansions MUST be double-quoted: "${var}", "$(command)", "$@". The only exceptions are inside [[ ]] tests and intentional word splitting with explicit IFS.
## Format
```bash
# Always quote
echo "${variable}"
result="$(some_command)"
command "${array[@]}"
```
## Good Examples
```bash
#!/usr/bin/env bash
set -euo pipefail
# Quoted variables
file_path="${1:?Missing argument}"
echo "Processing: ${file_path}"
# Quoted command substitution
current_date="$(date +%Y-%m-%d)"
file_count="$(find . -name '*.log' | wc -l)"
# Quoted array expansion
args=("--verbose" "--output" "/tmp/result.txt")
my_command "${args[@]}"
# Quoted in conditionals
if [[ "${status}" == "ready" ]]; then
echo "System is ready"
fi
# Quoted in loops
while IFS= read -r line; do
echo "Line: ${line}"
done < "${input_file}"
```
## Bad Examples
```bash
# BAD: Unquoted variable — breaks on spaces
file=/tmp/my file.txt
cat $file # Becomes: cat /tmp/my file.txt (two arguments!)
# BAD: Unquoted glob expansion
dir="*.txt"
echo $dir # Expands to matching filenames!
# BAD: Unquoted $@ in function
my_func() {
other_func $@ # Breaks arguments with spaces
}
# BAD: Unquoted command substitution
files=$(ls /tmp)
for f in $files; do # Word splits on spaces in filenames
rm $f
done
```
## The One Exception
```bash
# Intentional word splitting with controlled IFS
IFS=',' read -ra parts <<< "${csv_line}"
```
## Enforcement
- ShellCheck SC2086 catches all unquoted variable expansions
- Enable ShellCheck in CI and pre-commit hooks
- Use `${var}` brace syntax consistently for clarity