Bash error: "[: too many arguments"
Bash "[: too many arguments" means an unquoted variable with spaces word-split inside [ ]. Quote it, or use [[ ]], which never word-splits.
Error String
bash: [: too many arguments
Tldr
The `[` command (alias `test`) expects a fixed argument layout. An unquoted variable that holds whitespace word-splits into multiple args and breaks parsing. Quote the variable, or switch to `[[ ]]` which doesn't word-split.
Cause
In `[ "$x" = foo ]`, when `$x` is unquoted and equals "a b", `[` sees `[ a b = foo ]` — four arguments before `]` instead of three. The parser gives up with "too many arguments".
Repro
#!/usr/bin/env bash
x="hello world"
if [ $x = "hello" ]; then # too many arguments
echo match
fiFix
#!/usr/bin/env bash
x="hello world"
if [ "$x" = "hello" ]; then
echo match
fi
# Or use [[ ]] which handles whitespace correctly:
if [[ $x == "hello" ]]; then
echo match
fiExplanation
`[[ ]]` is a Bash keyword (not a command) and does not split unquoted variables. It also supports == with glob patterns and =~ for regex. Prefer it for any Bash-only script.
Related Shellcheck
SC2086
Deep Dive
Heading
How `[` counts its arguments
Body
`[` is an ordinary command whose last argument must be `]`. A binary comparison is exactly four words: `[`, left operand, operator, right operand, `]`. When an unquoted expansion contains whitespace, the shell splits it into several words before `[` ever runs, so the command receives five or more and reports "too many arguments". The same happens when the expansion contains a glob that matches multiple filenames, or when command substitution returns a multi-word line.
Heading
Empty values cause the mirror-image error
Body
If the unquoted variable is empty rather than multi-word, it disappears entirely and `[ = "hello" ]` becomes a three-word test — Bash then reports "unary operator expected" instead. Both messages have the same root cause: an unquoted expansion. Quoting fixes both at once, which is why SC2086 is the single highest-value lint rule in shell scripts.
Heading
When to prefer `[[ ]]`, `[ ]`, or `case`
Body
In a Bash-only script use `[[ ]]`: it is a shell keyword, does not word-split unquoted expansions, and supports `==` glob matching and `=~` regex. In a `#!/bin/sh` script `[[ ]]` is not available, so keep `[ ]` and quote every operand. For matching a value against several alternatives, `case "$x" in ...)` is clearer and safer than chained tests, and it works in both shells.
Checklist
Find the `[` on the reported line and count the words after expansion — an unquoted variable holding spaces is the usual culprit.
Quote every operand: `[ "$x" = "hello" ]`.
In a Bash script, switch the test to `[[ $x == "hello" ]]`.
Check for command substitution operands — `[ $(cmd) = x ]` splits whenever cmd prints more than one word.
Re-run a lint pass; SC2086 findings elsewhere in the script are the same bug waiting to happen.
Faq
Q
Does quoting break numeric comparisons?
A
No. `[ "$n" -gt 0 ]` works fine — quoting prevents word-splitting, it does not change how -gt parses the value.
Q
Why does `[[ ]]` not need quotes?
A
`[[ ]]` is parsed by the shell as a keyword, so unquoted expansions inside it are not word-split or glob-expanded. Quote the right-hand side anyway when you want a literal match rather than a pattern.
Q
Is `test` different from `[`?
A
No — `test` and `[` are the same command; `[` simply requires a closing `]`. Both split unquoted arguments identically.