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

Nei*_*ang 3 linux bash shell

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

例如:

root@ubuntu:~/testenv# cat test 
#!/bin/bash
SEND=1
if [ "$SEND" -eq 0 ]
        echo no
fi
Run Code Online (Sandbox Code Playgroud)

现在,让我们测试脚本:

root@ubuntu:~/testenv# bash -n test 
test: line 5: syntax error near unexpected token `fi'
test: line 5: `fi'
Run Code Online (Sandbox Code Playgroud)

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

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# 
Run Code Online (Sandbox Code Playgroud)

没啥事儿!

我还检查了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.
Run Code Online (Sandbox Code Playgroud)

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

Dav*_*d Z 5

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

[ "$SEND" -eq 0 ]
Run Code Online (Sandbox Code Playgroud)

那么你实际上是[用四个参数调用命令:

  1. 的价值 $SEND
  2. 字符串 -eq
  3. 字符串 0
  4. 字符串 ]

该命令[检查最后一个参数是否是](因为否则看起来很奇怪),然后将剩余的参数放在一起形成一个条件并返回测试条件的结果.

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

my_custom_conditional_test "$SEND" -eq 0
Run Code Online (Sandbox Code Playgroud)

很明显这很好,对吗?巴什也[以同样的方式思考.

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

您可以使用此对比[[,这确实或多或少同样的事情(测试条件),但由外壳赋予特殊的意义.[[是shell语法中的特殊标记,而不是命令.如果你写[[而不是[,并省略相应的尾随]],你打赌Bash会抱怨语法错误.