7

As a beginner, I did not find answered anywhere, the rules about spacing (grammar) and parsing.

For example.

Can I do

if [$# -eq 2] ; 
then 
    llll 
fi

or must I always have a blank or two between the objects, as

if [ $# -eq 2 ] ;
then
   llll
fi

and the second related question is about the difference between

if [[ $# -eq 2 ]] ;
then
wafwaf
fi

The concern I have is about spacing before/after [, ].

No searching has provided me with a set of rules.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578

1 Answers1

18

Spaces are required after [ and before ].

  1. [ is actually the name of a command, an alias for test. It's not a special symbol, it's just a command with an unusual name.

    $ help '['
    [: [ arg... ]
        Evaluate conditional expression.
    
        This is a synonym for the "test" builtin, but the last argument must
        be a literal `]', to match the opening `['.
    
  2. Because it's an ordinary command name and not a special character, a space is required after the [. If you omit the space and write [foo the shell will search the $PATH for a command named [foo.

    $ [ foo = foo ] && echo true
    true
    $ [foo = foo] && echo true
    [foo: command not found
    
  3. For readability's sake, [ expects its last argument to be exactly ]. Being an ordinary command-line argument, ] must have a space before it. If there's no space then the bracket will become the last character of the previous argument, and [ will complain about its last argument not being ].

    $ [ foo = foo]
    bash: [: missing `]'
    $ [ foo = 'foo]'
    bash: [: missing `]'
    

[[ is a bash enhancement with more features than [, namely saner handling of unquoted variable names. It requires the a space on both ends, same as [. However [[ is in fact special shell syntax and is parsed differently. It's not an "ordinary command" the way [ is.

For a detailed explanation of the difference between [ and [[, see:

Community
  • 1
  • 1
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 1
    +1. But perhaps it is worth clarifying that the fact that `[[` is special syntax does not make it self-delimiting. You need spaces (or self-delimiting characters) before and after `[[` and `]]`, just like `[` and `]`. The self-delimiting characters are space, tab and `|&()<>;`. (Which, due to bash's idiosyncrasies is not quite accurate since things like `((` and `>&` are tokens. But it's a good approximation.) – rici Sep 26 '13 at 16:19