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

linuxopen sourceoperating system

概述

在这里,我们将了解如何在不实际执行 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

此脚本检查用户输入的数字是否等于一。

现在让我们讨论一些语法验证方法。

使用 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'

值得注意的是,脚本失败了,提示"意外令牌附近的语法错误"。此外,让我们再次运行该脚本,并使用空字符串作为用户名 -

$ ./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 不会检查代码中缺少的关键字或类型。

使用 Shell 检查工具

使用 -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 脚本之前对其进行分析。


相关文章


有用资源