我们可以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"吧?那么,这怎么可能发生呢?
我猜你已经遇到了一个非常奇怪的关于shell实现单括号条件的方式的怪癖:[是命令,而不是特殊字符.查看系统可执行文件目录(可能/usr/bin),您将找到一个字面上命名的可执行文件[,它实现了此命令.当你写的东西像
[ "$SEND" -eq 0 ]
Run Code Online (Sandbox Code Playgroud)
那么你实际上是[用四个参数调用命令:
$SEND-eq0]该命令[检查最后一个参数是否是](因为否则看起来很奇怪),然后将剩余的参数放在一起形成一个条件并返回测试条件的结果.
现在,因为[是一个命令,用你喜欢的任何参数集调用该命令不是语法错误.当然,如果你不使用尾随],你将收到一个错误,但该错误来自命令[,而不是来自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会抱怨语法错误.