是否可以不执行而检查bash脚本语法?
使用Perl,我可以运行perl -c 'script name'。 bash脚本有任何等效命令吗?
相关:是否有像Shell一样的Lint或Perl :: Critic等静态分析工具?
bash -n scriptname
也许是一个明显的警告:这可以验证语法,但不会检查bash脚本是否尝试执行不在路径中的命令,例如ech hello而不是echo hello。
感谢您的提示,我一定会使用这个提示。奇怪的是,此选项未在bash手册页中列出:S ...
在bash的联机帮助页的" SHELL BUILTIN COMMANDS / set"下,记录了-n,并且在联机帮助页的开头,bash解释了set的所有单字符选项。
给(对我而言)不明显的警告,它也不会捕获由缺少空格if ["$var" =="string" ]而不是if ["$var" =="string" ]引起的错误
@Brynjar那是因为它只是语法检查。开括号不是语法,那就是要运行的函数的名称。 type [说" [是内置的shell"。它最终将委托给test程序,但也希望将其括起来。因此它类似于if test"$var",这不是作者的意思,但是在语法上有效(例如$ var的值为" a",那么我们将看到" bash:testa:未找到命令")。要点是,从语法上讲,没有缺少空间。
@JoshuaCheek:在这种情况下,仅当$var恰好扩展为空字符串时才调用内置[。如果$var扩展为非空字符串,则[与该字符串连接,并且被Bash解释为命令名(不是函数名),是的,在语法上是有效的,但是如您所述,显然不是目的。如果使用[[而不是[,即使[[是shell关键字(而不是内置关键字),您也会得到相同的结果,因为意外的字符串连接仍然会覆盖对关键字的识别。
@JoshuaCheek:Bash仍在这里进行语法检查:其检查的简单命令调用语法:["$var"在语法上是有效的命令名称表达式;同样,标记==和"$string"是有效的命令参数。 (通常,内置的[是用命令语法解析的,而[[-作为shell关键字-的解析方式是不同的。)shell内置的[不会委派给" test程序"(外部实用程序): bash,dash,ksh,zsh都具有[和test的内置版本,并且它们不调用其外部公用程序。
底线是:仅使用Bash本身,-n是您的最佳选择,但这不会引起许多初学者可能犯的错误;要捕获这些错误,请使用shellcheck.net或其CLI(如dvd818s答案中所述)。
@ mklement0很好,非常感谢您的解释!
另一个警告:不会考虑脚本中设置的选项。例如,如果添加shopt -s extglob,然后在case中执行foo@(bar|baz)),则bash -n将看到语法错误(bash -s extglob -n不会,但您永远不知道脚本的哪一部分受到影响)
@AloisMahdal不幸的是,在一般情况下这是不可能解决的,因为shell选项可以更改中间脚本,甚至可以基于只能在运行时知道的信息进行更改。
以下是man bash中的文档:-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.
是-n选项版本或特定于os的;在osx上似乎不起作用
时间改变了一切。这是一个提供Shell脚本在线语法检查的网站。
我发现检测常见错误非常强大。
关于ShellCheck
ShellCheck是用于sh / bash脚本的静态分析和整理工具。它主要专注于处理典型的初学者和中级语法错误和陷阱,在这些错误和陷阱中,shell仅仅给出神秘的错误消息或奇怪的行为,但它还报告了一些更高级的问题,在某些极端情况下,情况可能会导致延迟失败。
Haskell源代码可在GitHub上获得!
大提示;在OSX上,您现在还可以通过Homebrew:brew install shellcheck安装shellcheck.net CLI shellcheck。
也在debian&friends上:apt-get install shellcheck
对于可信任的Ubuntu,必须从trusty-backports安装此软件包。
这应该是公认的答案!
如上所述,需要信任依赖关系,可以按照以下说明在ubuntu 14.04中安装它:sudo apt-get -f install,然后:sudo sudo apt-get install shellcheck
这确实很有用,但是它不使用Bash的解析器,而是使用它自己的解析器。在大多数情况下,这已经足够好了,它可以识别解析问题和其他问题,但是至少有一种极端的情况(可能还有其他我未曾见过的情况)无法以完全相同的方式进行解析。
我还会在我编写的每个bash脚本上启用'u'选项,以进行一些额外的检查:
set -u
这将报告未初始化变量的用法,例如以下脚本" check_init.sh"
#!/bin/sh
set -u
message=hello
echo $mesage
运行脚本:
$check_init.sh
将报告以下内容:
./check_init.sh[4]: mesage: Parameter not set.
捕捉错别字非常有用
我总是在我的bash脚本中设置这些标志,如果通过这些标志,则最好设置" set -o errexit"" set -o nounset"" set -o pipefail"
为set -u +1,尽管这不能真正回答问题,因为您必须运行脚本来获取错误消息。甚至bash -n check_init.sh都没有显示警告
sh -n script-name
运行这个。如果脚本中有任何语法错误,则它将返回相同的错误消息。
如果没有错误,则显示出来时不会给出任何消息。您可以使用echo $?立即进行检查,这将返回0并确认成功,没有任何错误。
它对我很好。我在Linux OS Bash Shell上运行。
+1用于返回值检查。
尽管与bash语法检查不完全相关-使用set -x和set + x调试整个脚本或脚本的各个部分非常有用
谢谢你,这不知道-n,但是我想要的是@GuruM> sh -x test.sh,因为它显示了脚本的生成输出
是。我忘了提到您可以在命令行上执行以下操作:1)bash -x test.sh#这将在调试模式下运行整个脚本2)设置+ x; bash test.sh; set -x#在脚本运行之前/之后设置调试模式开/关在脚本中:a)#!/ bin / bash -x#在脚本顶部添加调试模式b)设置+ x;码; set -x#为脚本的任何部分添加调试模式
我实际上检查了当前目录中的所有bash脚本是否存在语法错误,而无需使用find工具运行它们:
例:
find . -name '*.sh' -exec bash -n {} \;
如果要将其用于单个文件,只需使用文件名编辑通配符。
空命令[冒号]在调试以查看变量的值时也很有用
set -x
for i in {1..10}; do
let i=i+1
: i=$i
done
set -
这是如何运作的?
它使用参数扩展
这行得通,因为set -x在执行之前显示每一行
如果在变量中需要目录中所有文件的有效性(git pre-commit钩子,构建lint脚本),则可以捕获" sh -n"或" bash -n"命令的stderr输出(请参见其他答案)中的变量,并根据该变量得出" if / else"
bashErrLines=$(find bin/ -type f -name '*.sh' -exec sh -n {} \; 2>&1 > /dev/null)
if ["$bashErrLines" !="" ]; then
# at least one sh file in the bin dir has a syntax error
echo $bashErrLines;
exit;
fi
根据需要将" sh"更改为" bash"
有用于IntelliJ IDEA的BashSupport插件,用于检查语法。
但是,如果文件不以.sh或与Bash脚本相关联的其他扩展名结尾,则将无法正常工作,如果您使用诸如ERB的模板工具生成脚本(则它们以.erb结尾),情况就是如此。如果您要解决此问题,请投票给youtrack.jetbrains.com/issue/IDEA-79574!