/errors/bash/too-many-arguments-in-test
bash: [: too many arguments
- tool
- Bash
- exit code
- 2
- versions
- bash 4.x, bash 5.x
- os
- linux, macos, windows
[: too many arguments is printed by the [ command (the same builtin as test) when it receives more words than any test form accepts. The usual reason is an unquoted variable that contains spaces: bash splits it into several words before [ sees them. Quote the variable or switch to [[ ... ]].
Reproduce it
name="john smith"
if [ $name = "john smith" ]; then
echo "match"
else
echo "no match"
fi
echo "status: $?"Output
bash: line 2: [: too many arguments no match status: 0
Without quotes, the test becomes [ john smith = "john smith" ], which is four arguments before ]. No valid test takes four arguments of that shape, so [ reports the error and returns status 2, and if takes the else branch.
How [ counts its arguments
[ is a command, so bash first performs word splitting and pathname expansion on every unquoted argument. The test then accepts a fixed set of shapes: one argument (true if non-empty), two (a unary operator and its operand, or ! and one argument), three (a binary operator between two operands) and so on up to a limited number with !, parentheses and the legacy -a and -o operators. Anything else is an error.
The empty-variable case fails differently: [ -n $x ] with an empty x becomes [ -n ], which is true because a single non-empty word is a valid test. Quoting avoids both problems.
Cause 1: unquoted variable with spaces
Quote the variable so it stays a single argument.
name="john smith"
if [ "$name" = "john smith" ]; then
echo "match"
fiOutput
match
Cause 2: a glob inside the test
[ -f *.txt ] expands the glob first. With two files it becomes [ -f a.txt b.txt ] and fails. Test the files one by one in a loop, or check for matches with compgen -G "*.txt".
Cause 3: [[ ]] avoids the problem in bash
The [[ keyword is parsed by the shell, so it does not split words or expand globs on the left side.
name="john smith"
if [[ $name = "john smith" ]]; then
echo "match"
fiOutput
match
Prefer [[ ]] in scripts that start with #!/usr/bin/env bash. Use quoted [ ] when the script must run under plain sh.
Prevent it
Quote all variable expansions unless you intend splitting, and run shellcheck on scripts: it reports unquoted variables in tests as SC2086. Use set -u (see the unbound variable page) to catch unset variables, and avoid -a and -o; chain two tests with && and ||.
FAQ
Is [ a command or syntax?
In bash, [ is a builtin command that is a synonym of test, and the closing ] is its last argument. That is why spaces around it are required and why unquoted words become separate arguments.
What exit status does the failed test return?
The error exits with status 2, which an if statement treats as false, so the else branch runs silently unless you read stderr.
Does [[ ]] work in sh scripts?
No. [[ ]] is a bash, ksh and zsh feature. A script started with #!/bin/sh on a POSIX shell such as dash must use [ ] with quoted variables.