【问题标题】:How do I syntax check a Bash script without running it?如何在不运行 Bash 脚本的情况下对其进行语法检查?
【发布时间】:2010-09-15 09:00:20
【问题描述】:

是否可以在不执行的情况下检查 bash 脚本语法?

使用 Perl,我可以运行 perl -c 'script name'。 bash 脚本是否有任何等效命令?

【问题讨论】:

标签: linux bash unix syntax gnu


【解决方案1】:
bash -n scriptname

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

【讨论】:

  • 在 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: command not found”)。关键是在语法上,没有空格。
  • @JoshuaCheek:仅当$var 恰好扩展为空字符串 时,才会调用内置[。如果$var 扩展为非空 字符串,[ 与该字符串连接 并被解释为命令 名称(不是function name) 由 Bash 编写,是的,这是 syntactically 有效的,但是,正如您所说,显然不是意图。如果您使用[[ 而不是[,即使[[ 是一个shell 关键字(而不是内置),您也会得到相同的结果,因为意外的字符串连接仍然会覆盖识别关键字。
  • @JoshuaCheek:Bash 仍然是 syntax-检查这里:它正在检查 simple-command invocation 语法:["$var"syntactically 一个有效的 command-name 表达式;同样,标记=="$string" 是有效的命令arguments。 (通常,内置 [ 使用 command 语法解析,而 [[ - 作为 shell keyword - 解析方式不同。)内置 shell [ 确实 不 委托到“test程序”(外部实用程序):bashdashkshzsh都有builtin 两个版本的 [test,它们确实调用它们的外部实用程序对应项。
【解决方案2】:
sh  -n   script-name 

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

它对我很有效。我在 Linux 操作系统、Bash Shell 上运行。

【讨论】:

  • 虽然与 bash 语法检查不完全相关 - 使用 set -x 和 set +x 来调试完整脚本或脚本部分非常有用
  • 感谢这个不知道不知道 -n 但我想要的是@GuruM > sh -x test.sh 因为它显示了脚本的生成输出
  • 是的。我忘了提到您可以在命令行中执行以下操作: 1) bash -x test.sh #this 在“调试模式”下运行整个脚本 2) set +x;重击测试.sh; set -x #set debug mode on/off before/after script run 在脚本中: a) #!/bin/bash -x #add 'debug mode' at the top of script b) set +x;代码;为脚本的任何部分设置 -x #add 'debug mode'
  • sh -n 可能不会检查脚本是否是有效的 Bash 脚本。它可能会给出假阴性。 sh 是一些 Bourne shell 变体,通常不是 Bash。例如在 Ubuntu Linux 中 realpath -e $(command -v sh) 给出 /bin/dash
【解决方案3】:

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

set -u 

这将报告未初始化变量的使用情况,如以下脚本'check_init.sh'

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

运行脚本:

$ check_init.sh

将报告以下内容:

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

非常有助于捕捉错别字

【讨论】:

  • 我总是在我的 bash 脚本中设置这些标志,如果它通过了这些,最好去 "set -o errexit" "set -o nounset" "set -o pipefail"
  • +1 for set -u 虽然这并不能真正回答问题,因为您必须运行脚本才能获取错误消息。甚至bash -n check_init.sh 都没有显示警告
【解决方案4】:

时间改变一切。 Here is a web site 为 shell 脚本提供在线语法检查。

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

关于ShellCheck

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

Haskell 源代码在 GitHub 上可用!

【讨论】:

  • 很棒的提示;在 OSX 上,您现在还可以通过 Homebrewbrew 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 的解析器而是它自己的。在大多数情况下,这已经足够好了,它可以识别解析和其他问题,但至少有一种极端情况(可能还有其他我没见过)它的解析方式并不完全相同。
【解决方案5】:

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

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

【讨论】:

  • 它使用参数扩展
  • 这行得通,因为set -x 在执行之前显示每一行
【解决方案6】:

BashSupport plugin 用于检查语法的 IntelliJ IDEA

【讨论】:

  • 但如果您的文件不以.sh 或与 Bash 脚本相关的其他扩展名结尾(如果您使用诸如 ERB 之类的模板工具(然后它们以.erb 结尾)。如果你想修复它,请投票给youtrack.jetbrains.com/issue/IDEA-79574
【解决方案7】:

我实际上在没有使用find 工具运行它们的情况下检查当前目录中的所有 bash 脚本是否存在语法错误:

示例:

find . -name '*.sh' -print0 | xargs -0 -P"$(nproc)" -I{} bash -n "{}"

如果您想将它用于单个文件,只需使用文件名编辑通配符即可。

【讨论】:

    【解决方案8】:

    如果你需要一个变量中所有文件的有效性(git pre-commit hook,build lint script),你可以捕获“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”

    【讨论】:

      【解决方案9】:

      仅用于验证语法:

      shellcheck[程序路径]

      对于运行程序只有在语法通过时,所以调试语法和执行:

      shellproof[程序路径]

      【讨论】:

        【解决方案10】:

        如果您启用语法检查,Bash shell 脚本将运行语法检查

        set -o noexec

        如果你想关闭语法检查

        set +o noexec

        【讨论】:

          最近更新 更多