如何在不运行Bash脚本的情况下对其进行语法检查?


Answers:


380
bash -n scriptname

也许是一个明显的警告:这可以验证语法,但不会检查您的bash脚本是否尝试执行不在您的路径中的命令(例如ech hello而不是)echo hello


9
在bash的联机帮助页中的“ SHELL BUILTIN COMMANDS / set”下,记录了-n,并且在联机帮助页的开头指出,bash会解释所有这样set做的单字符选项。
迅速

24
为了增加(对我而言)非明显的警告,它也不会捕获由缺少空格引起的错误,而if ["$var" == "string" ]不是if [ "$var" == "string" ]
Brynjar

11
@Brynjar那是因为它只是语法检查。左括号不是语法,而是要运行的函数的名称。type [说“ [是内置的shell”。它最终将委派给该test程序,但也期望将其括起来。因此,它就像if test"$var",不是作者的意思,而是在语法上有效的(例如$ var的值为“ a”,那么我们将看到“ bash:testa:未找到命令”)。要点是,从语法上讲,没有缺少空间。
2014年

2
@JoshuaCheek:[在这种情况下,只有在$var碰巧扩展为空字符串时才调用Builtin 。如果$var扩展到非空字符串,[串联与字符串被解释为一个命令名称(而不是函数被Bash,是的,就是名字)语法上有效的,但是,当你的状态,显然不是意图。如果您使用[[而不是[,即使[[是shell 关键字(而不是内置关键字),您也会得到相同的结果,因为意外的字符串连接仍然会覆盖关键字的识别。
mklement0

2
@JoshuaCheek:猛砸仍然语法 -检查这里:它检查简单的命令调用语法:["$var"语法上有效的命令名称表达; 同样,令牌=="$string"是有效的命令参数。(通常,内置[进行解析命令的语法,而[[-作为一个壳的关键字 -被分析是不同的。)的外壳内置[没有 委托给“ test程序”(外部工具): ,bash,,dash 都具有内置的两个版本和kshzsh[test,并且称其为外部公用事业公司。
mklement0 2015年

127

时间改变了一切。这是一个提供Shell脚本在线语法检查的网站

我发现检测常见错误非常强大。

在此处输入图片说明

关于ShellCheck

ShellCheck是用于sh / bash脚本的静态分析和整理工具。它主要侧重于处理典型的初学者和中级语法错误和陷阱,在这些错误和陷阱中,shell仅仅给出了隐秘的错误消息或奇怪的行为,但它还报告了一些更高级的问题,在某些极端情况下,情况可能会导致延迟失败。

Haskell源代码可在GitHub上获得!


5
大提示;在OSX上,你现在也可以安装shellcheck.net CLI,shellcheck通过自制brew install shellcheck
mklement0

3
也在debian&friends上:apt-get install shellcheck
另一个人

对于Ubuntu Trusty,必须从安装此软件包trusty-backports
Peterino

如上所述,需要信任依赖关系,可以按照以下说明在ubuntu 14.04中安装它:sudo apt-get -f install,然后:sudo sudo apt-get install shellcheck
zhihong

这确实很有用,但是它不使用Bash的解析器,而是使用它自己的解析器。在大多数情况下,这已经足够好了,它可以识别解析问题和其他问题,但是至少有一个极端的情况(可能还有其他我没有看到的情况),它的解析方式也不尽相同。
丹尼尔·H

38

我还会在我编写的每个bash脚本上启用'u'选项,以进行一些额外的检查:

set -u 

这将报告未初始化变量的用法,例如以下脚本“ check_init.sh”

#!/bin/sh
set -u
message=hello
echo $mesage

运行脚本:

$ check_init.sh

将报告以下内容:

./check_init.sh[4]:消息:未设置参数。

捕捉错别字非常有用


4
我在的bash脚本总是设置这些标志,如果通过这些,这是很好的去“集-o errexit”“集-o nounset”“集-o pipefail”
μολὼν.λαβέ

+1,set -u尽管这并不能真正回答问题,因为您必须运行脚本来获取错误消息。甚至没有bash -n check_init.sh显示该警告
rubo77'7

23
sh  -n   script-name 

运行这个。如果脚本中有任何语法错误,则它将返回相同的错误消息。如果没有错误,则显示出来时不会给出任何消息。您可以使用立即检查echo $?,它将返回0确认成功而没有任何错误。

它对我很好。我在Linux OS Bash Shell上运行。


1
尽管与bash语法检查不完全相关-使用set -x和set + x调试整个脚本或脚本的各个部分非常有用
GuruM 2012年

谢谢你,这不知道-n,但是我想要的是@GuruM> sh -x test.sh,因为它显示了脚本的生成输出
zzapper 2013年

1
是。我忘了提到您可以在命令行上执行以下操作:1)bash -x test.sh#这将在“调试模式”下运行整个脚本2)设置+ x;bash test.sh; set -x#在脚本运行之前/之后设置调试模式开/关在脚本中:a)#!/ bin / bash -x#在脚本顶部添加“调试模式” b)设置+ x;码; 为脚本的任何部分设置-x#添加“调试模式”
GuruM

sh -n可能不会检查该脚本是否是有效的Bash脚本。它可能会带来假阴性。sh是一些Bourne shell变体,通常不是Bash。例如,在Ubuntu Linux中realpath -e $(command -v sh),/ bin / dash
jarno

4

我实际上检查了当前目录中的所有bash脚本是否存在语法错误,而无需使用find工具运行它们:

例:

find . -name '*.sh' -exec bash -n {} \;

如果要将其用于单个文件,只需使用文件名编辑通配符。


3

空命令[冒号]在调试以查看变量的值时也很有用

set -x
for i in {1..10}; do
    let i=i+1
    : i=$i
done
set - 

它使用参数扩展
mug896

这行得通,因为set -x在执行之前显示了每一行
rubo77


1

如果在变量中需要目录中所有文件的有效性(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”

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.