Contents

在不运行的情况下检查BASH脚本的语法

1. 概述

在本教程中,我们将学习如何在不运行 Bash 脚本的情况下验证其语法。我们将仔细研究可用于此目的的一些 Bash 和第三方实用程序。

2. 设置

首先,让我们编写一个帮助程序脚本,我们将在本教程的大部分内容中使用它:

$ 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。

现在,让我们深入讨论并学习在语法上验证它的方法。

3.使用noexec模式进行语法检查

在某些情况下,我们可能希望在执行脚本之前对其进行语法验证。如果是这样**,我们可以使用*-n选项调用noexec*模式**。结果,Bash 将读取命令但不执行它们

让我们以noexec模式执行我们的unity_check.sh脚本:

$ 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语句从未被计算过。现在,我们看到该脚本通过了一些测试用例,但在一些测试用例中失败了。因此,在执行之前始终在语法上验证脚本是有意义的

让我们验证我们的脚本:

$ 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'

正如预期的那样,它会通知我们语法问题。我们还必须注意,没有要求用户输入,因为脚本没有执行。

4. 使用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

现在,让我们使用bash -n选项验证脚本 :

$ bash -n ./unity_check.sh
$ 

有趣的是,脚本通过了检查,没有报错。让我们执行脚本:

$ ./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 -n模式对脚本进行语法验证时,我们无法捕获此错误,因为“ [ ”不是语法的一部分。[ ” 是test 命令的替代选项,bash -n不检查缺少的命令或命令中的拼写错误。

5. 使用shell检查工具

正如在上一节中看到的,我们在使用bash -n选项时可能会遗漏一些错误。但是,我们可以使用一些第三方工具对我们的shell脚本进行静态分析。我们来分析一下ShellCheck 工具。

首先,让我们检查在 Debian/Ubuntu Linux 发行版上安装 ShellCheck 实用程序的命令:

$ apt install shellcheck

并且,RHEL/Fedora/CentOS 发行版的替代命令:

$ 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.
For more information:
  https://www.shellcheck.net/wiki/SC1049 -- Did you forget the 'then' for thi...
  https://www.shellcheck.net/wiki/SC1050 -- Expected 'then'.
  https://www.shellcheck.net/wiki/SC1072 -- Unexpected keyword/token. Fix any...

正如预期的那样,它通知我们缺少then语句。现在,让我们使用 ShellCheck 实用程序验证第 4 节中的脚本:

$ shellcheck unity_check.sh
In unity_check.sh line 2:
read -p "Enter the input: " num1
^--^ SC2162: read without -r will mangle backslashes.
In unity_check.sh line 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.
For more information:
  https://www.shellcheck.net/wiki/SC2171 -- Found trailing ] outside test. Ad...
  https://www.shellcheck.net/wiki/SC2215 -- This flag is used as a command na...
  https://www.shellcheck.net/wiki/SC2162 -- read without -r will mangle backs...

伟大的!它也能够识别缺失的括号,而bash -n命令无法识别。