BASH语法检查调试模式故障?

时间:2017-01-03 07:58:48

标签: linux bash shell

我们可以使用bash -n script.sh来验证shell脚本的语法。但是,当我尝试测试此函数时,我注意到此选项无法找到所有语法错误。

例如:

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

现在,让我们测试一下脚本:

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

工作正常。但是,如果我只删除其中一个括号:

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# 

什么都没发生!

我还检查了bash的手册页,它描述了" -n"是:

 -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.

这是一个脚本文件,所以它不应该是一个"交互式shell"对?那么,这怎么可能发生呢?

1 个答案:

答案 0 :(得分:5)

我猜你已经遇到了shell实现单括号条件的方式的一个非常奇怪的怪癖:[命令,而不是特殊字符。查看系统可执行文件目录(可能是/usr/bin),您将找到一个名为[的可执行文件,它实现了此命令。当你写像

这样的东西
[ "$SEND" -eq 0 ]

然后你实际上用四个参数调用命令[

  1. $SEND
  2. 的值
  3. 字符串-eq
  4. 字符串0
  5. 字符串]
  6. 命令[检查最后一个参数是否为](因为它看起来很奇怪),然后将剩下的参数放在一起形成一个条件并返回测试条件的结果。 / p>

    现在,因为[是一个命令,所以使用您喜欢的任何参数集调用该命令不是语法错误。当然,如果您不在尾随],您将收到错误,但该错误来自shell中的[命令,而不是。这意味着您必须实际运行脚本才能获得错误 - 语法检查器不会看到任何错误。就bash而言,[只是一个命令名称,与my_custom_conditional_test没有区别,如果你要写

    my_custom_conditional_test "$SEND" -eq 0
    
    很明显这很好,对吗? Bash以同样的方式思考[

    我应该注意,为了提高效率,bash实际上并没有使用可执行文件/usr/bin/[;它有自己的[内置实现。但是人们期望[以相同的方式行事,无论它是否内置于shell中,因此Bash语法检查器无法给出自己的[特殊处理。由于在没有尾随/usr/bin/[的情况下调用]不会出现语法错误,因此在没有[的情况下调用内置]不会是语法错误。

    您可以将此与[[进行对比,[[或多或少地执行相同的操作(测试条件),但 具有shell的特殊含义。 [[是shell语法中的特殊标记,而不是命令。如果您编写[而不是]],并且省略了相应的尾随rm ~/.appcfg_oauth2_tokens ,则您认为Bash会抱怨语法错误。