如何在 Linux 中不运行 Bash 脚本的情况下检查其语法?
概述
在这里,我们将了解如何验证 Bash 脚本的语法正确性,而无需实际执行它。我们将检查一些可用于此任务的 Bash 和外部工具。
配置
让我们首先编写一个简单的脚本,我们将在整个教程的大多数示例中使用它。
$ cat unity_check.sh #! /bin/bash read -p "Enter the input: " num1 if [ -z "$num1" ] then echo "The number is empty" exit 0 fi if [ "${num1}" -eq 1 ] then echo "Number entered is 1" else echo "Not equal to One !!" fi
此脚本检查人类输入的数字是否等于 1。
现在让我们讨论一些用于语法验证的方法。
使用 noexec 模式进行语法检查
我们有时可能希望运行脚本而不实际执行它们。例如,如果我们试图在运行命令之前测试其是否有效,我们可能会使用 -n(noexec)标志。因此,Bash 会读取命令,但不会执行它们。
让我们在非可执行(noexec)模式下运行我们的 unity_check.py 脚本
$ bash -n ./unity_check.sh $
如果没有语法错误,让我们稍微修改一下代码,并删除第二个 if 语句的 then 语句。
$ cat unity_check_error.sh #! /bin/bash read -p "Enter the input: " num1 if [ -z "$num1" ] then echo "The number is empty" exit 0 fi if [ "${num1}" -eq 1 ] echo "Number entered is 1" else echo "Not equal to One !!" fi
让我们尝试运行脚本。
$ ./unity_check_error.sh Enter the input: 2 ./unity_check_error.sh: line 10: syntax error near unexpected token `else' ./unity_check_error.sh: line 10: `else'
值得注意的是,脚本失败了,并指出“Syntax Error Near Unexpected Token”作为原因。此外,让我们再次使用空字符串作为用户名运行它 -
$ ./unity_check_error.sh Enter the input: The number is empty
在这里,第一个 if 语句没有执行,因为第二个 if 语句为真。但是,第二个 if 语句为假,所以整个事情都失败了。
让我们测试我们的脚本 -
$ bash -n ./unity_check_error.sh ./unity_check_error.sh: line 10: syntax error near unexpected token `else' ./unity_check_error.sh: line 10: `else'
它告诉我们代码中有一些语法错误。我们还必须在此处注意,我们没有请求任何用户输入,因为脚本没有执行。
使用 noexec 模式的注意事项
我们将再次修改我们的脚本 - 此第二次迭代从第一个 if 语句中删除了方括号。
$ cat unity_check.sh #! /bin/bash read -p "Enter the input: " num1 if -z "$num1" ] then echo "The number is empty" exit 0 fi if [ "${num1}" -eq 1 ] then echo "Number entered is 1" else echo "Not equal to One !!" fi
现在让我们使用“-n”标志运行脚本进行验证。
$ bash -n ./unity_check.sh $
当我们运行 Python 代码时,它似乎通过了测试,没有任何错误。让我们执行代码 -
$ ./unity_check.sh Enter the input: ./unity_check.sh: line 3: -z: command not found ./unity_check.sh: line 8: [: : integer expression expected Not equal to One !!
现在,它说出现错误了!
当我们使用 bash -v 模式运行脚本时,Bash 没有捕获此错误,因为“["在 shell 语言中不是有效字符。“["用于代替 test 关键字,而 bash -v 不会检查代码中缺少的关键字或类型。
使用 ShellCheck 工具
使用 -n 选项时,我们可能会错过一些错误。但是我们可以使用一些第三方 shell 脚本静态分析工具。现在让我们分析 ShellCheck 工具。
首先,我们需要安装名为 ShellChecks 的 shell 脚本检查工具。我们可以通过运行以下命令来做到这一点 -
$ apt install shellcheck
以及 Red Hat Enterprise Linux (RHEL)、Fedora 和的替代命令
$ yum install ShellCheck
现在,让我们使用此工具验证第 3 节中的脚本 -
$ shellcheck unity_check_error.sh In unity_check_error.sh line 8: if [ "${num1}" -eq 1 ] ^-- SC1049: Did you forget the 'then' for this 'if'? ^-- SC1073: Couldn't parse this if expression. Fix to allow more checks. In unity_check_error.sh line 10: else ^-- SC1050: Expected 'then'. ^-- SC1072: Unexpected keyword/token. Fix any mentioned problems and try again.
正如我们所期望的那样,它告诉我们缺少 then 子句。现在,我们需要使用 ShellCheck 工具验证我们的脚本。
$ shellcheck unity_check.sh In unity_check.sh line 2: read -p "Enter the input: " num1 ^--^ SC2162: read without -r will mangle backslashes
在 unity_check.sh 第 3 行 -
if -z "$num1" ] ^-- SC2215: This flag is used as a command name. Bad line break or missing [ .. ]? ^-- SC2171: Found trailing ] outside test. Add missing [ or quote if intentional.
太棒了!Bash -n 也能够识别额外的括号,而 grep -E '\(.*\)' file.txt 无法识别。
结论
我们查看了在实际执行 Bash 脚本之前验证其语法的不同方法。
我们首先了解了 Bash 的 noexec(不执行)模式。然后,我们查看了它的一些局限性。最后,我们使用了一个名为 ShellCheck 的第三方实用程序来分析我们的 shell 脚本,然后再运行它们。