Meaning of "[: too many arguments" error from if [] (square brackets)

344,953

Solution 1

If your $VARIABLE is a string containing spaces or other special characters, and single square brackets are used (which is a shortcut for the test command), then the string may be split out into multiple words. Each of these is treated as a separate argument.

So that one variable is split out into many arguments:

VARIABLE=$(/some/command);  
# returns "hello world"

if [ $VARIABLE == 0 ]; then
  # fails as if you wrote:
  # if [ hello world == 0 ]
fi 

The same will be true for any function call that puts down a string containing spaces or other special characters.


Easy fix

Wrap the variable output in double quotes, forcing it to stay as one string (therefore one argument). For example,

VARIABLE=$(/some/command);
if [ "$VARIABLE" == 0 ]; then
  # some action
fi 

Simple as that. But skip to "Also beware..." below if you also can't guarantee your variable won't be an empty string, or a string that contains nothing but whitespace.


Or, an alternate fix is to use double square brackets (which is a shortcut for the new test command).

This exists only in bash (and apparently korn and zsh) however, and so may not be compatible with default shells called by /bin/sh etc.

This means on some systems, it might work from the console but not when called elsewhere, like from cron, depending on how everything is configured.

It would look like this:

VARIABLE=$(/some/command);
if [[ $VARIABLE == 0 ]]; then
  # some action
fi 

If your command contains double square brackets like this and you get errors in logs but it works from the console, try swapping out the [[ for an alternative suggested here, or, ensure that whatever runs your script uses a shell that supports [[ aka new test.


Also beware of the [: unary operator expected error

If you're seeing the "too many arguments" error, chances are you're getting a string from a function with unpredictable output. If it's also possible to get an empty string (or all whitespace string), this would be treated as zero arguments even with the above "quick fix", and would fail with [: unary operator expected

It's the same 'gotcha' if you're used to other languages - you don't expect the contents of a variable to be effectively printed into the code like this before it is evaluated.

Here's an example that prevents both the [: too many arguments and the [: unary operator expected errors: replacing the output with a default value if it is empty (in this example, 0), with double quotes wrapped around the whole thing:

VARIABLE=$(/some/command);
if [ "${VARIABLE:-0}" == 0 ]; then
  # some action
fi 

(here, the action will happen if $VARIABLE is 0, or empty. Naturally, you should change the 0 (the default value) to a different default value if different behaviour is wanted)


Final note: Since [ is a shortcut for test, all the above is also true for the error test: too many arguments (and also test: unary operator expected)

Solution 2

Just bumped into this post, by getting the same error, trying to test if two variables are both empty (or non-empty). That turns out to be a compound comparison - 7.3. Other Comparison Operators - Advanced Bash-Scripting Guide; and I thought I should note the following:

  • I used -e thinking it means "empty" at first; but that means "file exists" - use -z for testing empty variable (string)
  • String variables need to be quoted
  • For compound logical AND comparison, either:
    • use two tests and && them: [ ... ] && [ ... ]
    • or use the -a operator in a single test: [ ... -a ... ]

Here is a working command (searching through all txt files in a directory, and dumping those that grep finds contain both of two words):

find /usr/share/doc -name '*.txt' | while read file; do \
  a1=$(grep -H "description" $file); \
  a2=$(grep -H "changes" $file); \
  [ ! -z "$a1" -a ! -z "$a2"  ] && echo -e "$a1 \n $a2" ; \
done

Edit 12 Aug 2013: related problem note:

Note that when checking string equality with classic test (single square bracket [), you MUST have a space between the "is equal" operator, which in this case is a single "equals" = sign (although two equals' signs == seem to be accepted as equality operator too). Thus, this fails (silently):

$ if [ "1"=="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] && [ "1"="1" ] ; then echo A; else echo B; fi 
A
$ if [ "1"=="" ] && [ "1"=="1" ] ; then echo A; else echo B; fi 
A

... but add the space - and all looks good:

$ if [ "1" = "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" = "" -a "1" = "1" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" -a "1" == "1" ] ; then echo A; else echo B; fi 
B

Solution 3

Another scenario that you can get the [: too many arguments or [: a: binary operator expected errors is if you try to test for all arguments "$@"

if [ -z "$@" ]
then
    echo "Argument required."
fi

It works correctly if you call foo.sh or foo.sh arg1. But if you pass multiple args like foo.sh arg1 arg2, you will get errors. This is because it's being expanded to [ -z arg1 arg2 ], which is not a valid syntax.

The correct way to check for existence of arguments is [ "$#" -eq 0 ]. ($# is the number of arguments).

Solution 4

I also faced same problem. @sdaau answer helped me in logical way. Here what I was doing which seems syntactically correct to me but getting too many arguments error.

Wrong Syntax:

if [ $Name != '' ] && [ $age != '' ] && [ $sex != '' ] && [ $birthyear != '' ]  && [ $gender != '' ] 
then
    echo "$Name"
    echo "$age"
    echo "$sex"
    echo "$birthyear"
    echo "$gender"
else
    echo "Enter all the values"
fi

in above if statement, if I pass the values of variable as mentioned below then also I was getting syntax error

export "Name"="John"
export "age"="31"
export "birthyear"="1990"
export "gender"="M"

With below syntax I am getting expected output. Correct syntax:

if [ "$Name" != ""  -a  "$age" != ""  -a  "$sex" != ""  -a  "$birthyear" != ""   -a  "$gender" != "" ] 
then
    echo "$Name"
    echo "$age"
    echo "$sex"
    echo "$birthyear"
    echo "$gender"
else
    echo "it failed"
fi

There are few points which we need to keep in mind

  1. use "" instead of ''
  2. use -a instead of &&
  3. put space before and after operator sign like [ a = b], don't use as [ a=b ] in if condition

Hence above solution worked for me !!!

Solution 5

Some times If you touch the keyboard accidentally and removed a space.

if [ "$myvar" = "something"]; then
    do something
fi

Will trigger this error message. Note the space before ']' is required.

Share:
344,953

Related videos on Youtube

user56reinstatemonica8
Author by

user56reinstatemonica8

See: https://meta.stackexchange.com/q/336526/178621

Updated on July 08, 2022

Comments

  • user56reinstatemonica8
    user56reinstatemonica8 almost 2 years

    I couldn't find any one simple straightforward resource spelling out the meaning of and fix for the following BASH shell error, so I'm posting what I found after researching it.

    The error:

    -bash: [: too many arguments
    

    Google-friendly version: bash open square bracket colon too many arguments.

    Context: an if condition in single square brackets with a simple comparison operator like equals, greater than etc, for example:

    VARIABLE=$(/some/command);
    if [ $VARIABLE == 0 ]; then
      # some action
    fi 
    
  • Jo So
    Jo So over 11 years
    An even better way is i=$(some_command); i=$((i)); if [ "$i" == 0 ] ...
  • jww
    jww almost 8 years
    Could you provide a bash shell example of ((A || B) && C)?
  • splaisan
    splaisan almost 8 years
    please see question 3826425 and 14964805
  • ivanleoncz
    ivanleoncz almost 7 years
    I experienced a problem where a Shellscript using BASH as interpreter, when executed via terminal, was going ok, but when executed via Crontab, was having failures like this and sending local email via Postfix, informing this error and I figured out, that there was a IF for a variable that had special characters. Double quotes saved my life. Thank you :)!
  • Timothy Swan
    Timothy Swan over 6 years
    This really isn't that useful of an answer because it doesn't show you how to contain the command completely within the square brackets, which is needed if there is a loop, for example.
  • Joe Holloway
    Joe Holloway over 5 years
    I think that results in a different syntax error, such as: line 21: [: missing `]'
  • tripleee
    tripleee almost 4 years
    No need to export a variable which isn't used by a subprocess.