3

We can use bash -n script.sh to validate the syntax of a shell script. However, when I was trying to test this function, I noticed not all the syntax errors could be found by this option.

For example:

root@ubuntu:~/testenv# cat test 
#!/bin/bash
SEND=1
if [ "$SEND" -eq 0 ]
        echo no
fi

Now, let's test the script:

root@ubuntu:~/testenv# bash -n test 
test: line 5: syntax error near unexpected token `fi'
test: line 5: `fi'

It works fine. However, if I just remove one of the bracket:

root@ubuntu:~/testenv# cat test     
#!/bin/bash
SEND=1
if [ "$SEND" -eq 0 
then 
        echo no
fi
root@ubuntu:~/testenv# bash -n test 
root@ubuntu:~/testenv# 

Nothing happened!

I also checked the man page of bash, it describes the "-n" is:

 -n               Read  commands  but  do not execute them.  This may be used to check a
                  shell script for  syntax  errors.   This  is  ignored  by  interactive
                  shells.

It is a script file, so it shouldn't be an "interactive shell" right? So,how could this happen?

10
  • Please take a look: shellcheck.net Commented Jan 3, 2017 at 8:04
  • @NeilWang: Looks valid! Do highlight the same, people may mis-interpret it Commented Jan 3, 2017 at 8:05
  • @Inian In the second example, I missed a close bracket "]", but the syntax checker didn't find! Please execute them on your own box, you will find it will throw an error. Commented Jan 3, 2017 at 8:08
  • @NeilWang: You can't expect to catch that error, it ain't a syntax violation, [ is a shell built-in Commented Jan 3, 2017 at 8:09
  • 1
    This is a good question, why do people want to close it and downvoted it? Commented Jan 3, 2017 at 9:13

1 Answer 1

5

I'm guessing you have run into a very strange quirk of the way the shell implements single-bracketed conditionals: [ is a command, not a special character. Look in your system executable directory (probably /usr/bin) and you will find an executable file literally named [ which implements this command. When you write something like

[ "$SEND" -eq 0 ]

then you're actually invoking the command [ with four arguments:

  1. The value of $SEND
  2. The string -eq
  3. The string 0
  4. The string ]

The command [ checks that the last argument is ] (because it would look weird otherwise), then puts the remaining arguments together to form a condition and return the result of testing the condition.

Now, because [ is a command, it's not a syntax error to invoke that command with any set of arguments you like. Sure, if you leave off the trailing ], you will get an error, but that error comes from the command [, not from the shell. That means you have to actually run the script to get the error - the syntax checker won't see anything wrong with it. As far as bash is concerned, [ is just a command name, no different from, say, my_custom_conditional_test, and if you were to write

my_custom_conditional_test "$SEND" -eq 0

it would be obvious that this is fine, right? Bash thinks of [ the same way.

I should note that for efficiency, bash doesn't actually use the executable file /usr/bin/[; it has its own builtin implementation of [. But people expect [ to act the same way regardless of whether it's built in to the shell or not, so the Bash syntax checker can't give its own [ special treatment. Since it wouldn't be a syntax error to invoke /usr/bin/[ with no trailing ], it can't be a syntax error to invoke the builtin [ without a ].

You can contrast this with [[, which does more or less the same thing (testing a condition) but is given special meaning by the shell. [[ is a special token in shell syntax, not a command. If you write [[ instead of [, and you omit the corresponding trailing ]], you bet Bash is going to complain about a syntax error.

Sign up to request clarification or add additional context in comments.

1 Comment

You are exactly damn right! I had never known there is a [ under /usr/bin. Thank you for solving my concerns.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.