What does SC2086 mean?
SC2086, "Double quote to prevent globbing and word splitting", is ShellCheck's info-level warning that a $variable or ${expansion} is used without double quotes in a position where bash will split its value on whitespace and expand any glob characters in it before the command sees it. Info is the lowest severity ShellCheck shows by default. That is a poor guide to how much damage the pattern does.
What actually breaks?
Three files in a directory and a four-line script, run on this box with bash 5.3.9:
Two files gone, neither of them the one the script named, and exit code 0 because both arguments rm received existed. set -euo pipefail did nothing here; there was no error to catch. Word splitting turned rm $report into rm quarterly report.txt.
The glob half of the warning:
Unquoted, *.log is expanded against the current directory before echo runs. find . -name $pattern does the same thing and searches for one literal filename instead of a pattern; ShellCheck reports that variant as SC2061.
What does ShellCheck say, and what is the fix?
The fix is the suggestion:
One file deleted, the right one. Double quotes keep the expansion as a single argument and switch off glob expansion of its contents. $report inside double quotes is still expanded; only single quotes stop that.
Where else does SC2086 show up?
Inside [ ]. [ is a command, so an empty variable changes the argument count:
The test fails with a message on stderr, the script keeps going, and the branch you were guarding is skipped. [ "$name" = "root" ] is what ShellCheck suggests. Inside [[ ]] bash does not split, so ShellCheck stays quiet there.
In for loops. for f in $files is the one place where splitting is often on purpose:
ShellCheck 0.11.0 does not flag this loop at all. It treats an unquoted variable in for ... in as intentional, and the output is still wrong for any element with a space. The fix is a list that can hold spaces, which in bash means an array.
With arrays. Unquoted ${files[@]} is not SC2086. It is SC2068, an error: "Double quote array expansions to avoid re-splitting elements." Same fix, "${files[@]}", and the loop above prints two lines instead of three.
Intended splitting. A variable that holds a list of flags:
ShellCheck flags it because it cannot know the split is wanted. Two honest ways out: make it an array, opts=(-r -n) and grep "${opts[@]}" pattern ., which ShellCheck accepts silently, or keep the string and disable the check on that one line with the reason written down.
When should I disable SC2086, and how?
Disable it only where the split is the point and an array would be awkward: flag strings read from a config file, or arguments handed through a thin wrapper. Every other case is a bug waiting for a filename with a space in it.
One line, with the reason:
The directive covers the next command only. For the whole file, put the same line after the shebang and before the first command. For the whole project, a .shellcheckrc in the repo root with disable=SC2086. For one run, shellcheck --exclude=SC2086 script.sh, or shellcheck -S warning script.sh, which hides every info-level check including this one.
Two of the searches that led to this page asked the opposite question: lint for this rule and nothing else.
That prints only SC2086 findings and still exits 1 when there are any, so it works as a CI gate that enforces quoting while a repo is still working through its other findings. The short form is -i, and codes combine with commas.
Related codes
- SC2068 — the same problem for arrays, at error severity. See Bash Arrays.
- SC2046 — the same problem for
$(command)output. See the SC2046 deep dive. - SC2061 — an unquoted glob handed to
find -name. - SC2048 — unquoted
$*; use"$@".
Any other code: paste it into the ShellCheck Error Decoder.