我们可以使用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"对?那么,这怎么可能发生呢?
答案 0 :(得分:5)
我猜你已经遇到了shell实现单括号条件的方式的一个非常奇怪的怪癖:[
是命令,而不是特殊字符。查看系统可执行文件目录(可能是/usr/bin
),您将找到一个名为[
的可执行文件,它实现了此命令。当你写像
[ "$SEND" -eq 0 ]
然后你实际上用四个参数调用命令[
:
$SEND
-eq
0
]
命令[
检查最后一个参数是否为]
(因为它看起来很奇怪),然后将剩下的参数放在一起形成一个条件并返回测试条件的结果。 / 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会抱怨语法错误。