使用 ShellCheck lint 脚本分析工具改进你的 bash/sh shell 脚本
ShellCheck是一个静态分析 shell 脚本的工具。你可以使用它来查找 shell 脚本中的错误。它是用 Haskell 编写的。此工具为 bash/sh shell 脚本提供警告和建议。让我们看看如何在 Linux 或类 Unix 系统上安装和使用 ShellCheck 来增强你的 shell 脚本、避免错误并提高生产力。
Shell 脚本很有趣。在 Shell 脚本中创建漂亮(也许丑陋)的东西很有用。Shell 脚本对于自动执行您在提示符下重复的进程很有用。
ShellCheck lint脚本分析工具
shell 脚本的质量可能很危险。大多数新用户、系统管理员和开发人员会使用 StackOverflow、Google、有关 Linux/Unix 的问答网站来复制和粘贴代码。这可能会导致大量不良代码和错误。例如,灾难性的 rm 命令,因为 VAR 根本没有定义:
# rm -rf "$VAR/*"
您可以在使用 shellcheck 等 linting 工具编写 shell 脚本时修复许多此类问题。让我们保持安全并使用 ShellCheck 工具执行 shell 脚本分析。
安装 ShellCheck
在本地安装 ShellCheck 的最简单方法是通过您的软件包管理器,例如 apt/apt-get/yum 和适合您的 Linux 发行版或 Unix 变体的软件包管理器。根据您的发行版运行命令。
在 Debian/Ubuntu Linux 上安装 ShellCheck
输入以下apt 命令/ apt-get 命令:
$ sudo apt install shellcheck
示例输出:
[sudo] password for vivek: Reading package lists... Done Building dependency tree Reading state information... Done The following NEW packages will be installed: shellcheck 0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded. Need to get 1,841 kB of archives. After this operation, 15.5 MB of additional disk space will be used. Get:1 http://in.archive.ubuntu.com/ubuntu artful/universe amd64 shellcheck amd64 0.4.6-1 [1,841 kB] Fetched 1,841 kB in 42s (43.4 kB/s) Selecting previously unselected package shellcheck. (Reading database ... 196100 files and directories currently installed.) Preparing to unpack .../shellcheck_0.4.6-1_amd64.deb ... Unpacking shellcheck (0.4.6-1) ... Setting up shellcheck (0.4.6-1) ... Processing triggers for man-db (2.7.6.1-2) ...
在 CentOS/RHEL/Fedora/Oracle Linux 上安装 ShellCheck
首先在 CentOS/RHEL 上启用 EPEL repo:
$ sudo yum -y install epel-release
接下来,输入以下yum 命令:
$ sudo yum install ShellCheck
示例输出:
Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * base: centos.excellmedia.net * epel: mirror.nes.co.id * extras: mirrors.vonline.vn * updates: centos-hcm.viettelidc.com.vn Resolving Dependencies --> Running transaction check ---> Package ShellCheck.x86_64 0:0.3.5-1.el7 will be installed --> Processing Dependency: ghc(ShellCheck-0.3.5-297097a7f5fa37100847be7f096be51e) for package: ShellCheck-0.3.5-1.el7.x86_64 ..... .. ... Dependencies Resolved =============================================================================== Package Arch Version Repository Size =============================================================================== Installing: ShellCheck x86_64 0.3.5-1.el7 epel 495 k Installing for dependencies: ghc-ShellCheck x86_64 0.3.5-1.el7 epel 540 k ghc-array x86_64 0.4.0.1-26.4.el7 epel 113 k ghc-base x86_64 4.6.0.1-26.4.el7 epel 1.6 M ghc-bytestring x86_64 0.10.0.2-26.4.el7 epel 182 k ghc-containers x86_64 0.5.0.0-26.4.el7 epel 287 k ghc-deepseq x86_64 1.3.0.1-26.4.el7 epel 45 k ghc-directory x86_64 1.2.0.1-26.4.el7 epel 59 k ghc-filepath x86_64 1.3.0.1-26.4.el7 epel 60 k ghc-json x86_64 0.7-4.el7 epel 96 k ghc-mtl x86_64 2.1.2-27.el7 epel 33 k ghc-old-locale x86_64 1.0.0.5-26.4.el7 epel 50 k ghc-parsec x86_64 3.1.3-31.el7 epel 105 k ghc-pretty x86_64 1.1.1.0-26.4.el7 epel 57 k ghc-regex-base x86_64 0.93.2-29.el7 epel 28 k ghc-regex-compat x86_64 0.95.1-35.el7 epel 15 k ghc-regex-posix x86_64 0.95.2-30.el7 epel 47 k ghc-syb x86_64 0.4.0-35.el7 epel 39 k ghc-text x86_64 0.11.3.1-2.el7 epel 379 k ghc-time x86_64 1.4.0.1-26.4.el7 epel 187 k ghc-transformers x86_64 0.3.0.0-34.el7 epel 100 k ghc-unix x86_64 2.6.0.1-26.4.el7 epel 160 k Transaction Summary =============================================================================== Install 1 Package (+21 Dependent packages) Total download size: 4.6 M Installed size: 28 M Is this ok [y/d/N]: y Downloading packages: (1/22): ghc-bytestring-0.10.0.2-26.4.el7.x86_64.rpm | 182 kB 00:09 (2/22): ghc-array-0.4.0.1-26.4.el7.x86_64.rpm | 113 kB 00:09 .... .. ... ghc-parsec.x86_64 0:3.1.3-31.el7 ghc-pretty.x86_64 0:1.1.1.0-26.4.el7 ghc-regex-base.x86_64 0:0.93.2-29.el7 ghc-regex-compat.x86_64 0:0.95.1-35.el7 ghc-regex-posix.x86_64 0:0.95.2-30.el7 ghc-syb.x86_64 0:0.4.0-35.el7 ghc-text.x86_64 0:0.11.3.1-2.el7 ghc-time.x86_64 0:1.4.0.1-26.4.el7 ghc-transformers.x86_64 0:0.3.0.0-34.el7 ghc-unix.x86_64 0:2.6.0.1-26.4.el7 Complete!
如果您使用的是 Fedora Linux,请运行以下 dnf 命令:
$ sudo dnf install ShellCheck
在 Arch Linux 上安装 ShellCheck
输入以下 pacman 命令:
$ sudo pacman -S shellcheck
在 Gentoo Linux 上安装 ShellCheck
输入以下 emerge 命令:
$ sudo emerge --ask shellcheck
在 OpenSUSE Linux 上安装 ShellCheck
运行以下 zypper 命令:
$ sudo zypper in ShellCheck
macOS Unix 安装 ShellCheck
如果您使用的是 MacPorts,请尝试以下端口命令:
$ port install shellcheck
如果您在 macOS/OS X 上使用 Homebrew,请在 macOS 上安装 Homebrew,然后输入以下 brew 命令:
$ brew install shellcheck
Alpine Linux 安装 ShellCheck
执行apk 命令:
# apk add shellcheck
如何使用 ShellCheck
让我们看看带有cat 命令的示例 shell 脚本:
$ cat -n backupme
示例输出:
1 #!/bin/bash 2 t="/tmp/exclude.$$" 3 source ~/.backup.conf 4 >$t 5 for w in $WHATNOT 6 do 7 echo $w >> $t 8 done 9 rsync $OPT -avr --exclude-from=$t $WHAT $SERVER:$WHERE 10 rm -rf $t
在终端中运行 shellcheck backupme:
$ shellcheck backupme
示例输出:
图 01:ShellCheck 正在运行(点击放大)
$ cat -n backupme
示例输出:
1 #!/bin/bash 2 t="/tmp/exclude.$$" 3 source ~/.backup.conf 4 touch $t 5 for w in $WHATNOT 6 do 7 echo "$w" >> $t 8 done 9 rsync "$OPT" -avr --exclude-from=$t "$WHAT" "$SERVER:$WHERE" 10 rm -rf "$t"
另一个会话使用了shell脚本静态分析工具shellcheck:
In /home/vivek/bin/faqtoc line 2: code="" ^-----------------^ SC2124: Assigning an array to a string! Assign as array, or use * instead of @ to concatenate. In /home/vivek/bin/faqtoc line 5: [ $? -eq 0 ] && { echo -n "$code" | xclip -sel clip; } ^-- SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?. For more information: https://www.shellcheck.net/wiki/SC2124 -- Assigning an array to a string! A... https://www.shellcheck.net/wiki/SC2181 -- Check exit code directly with e.g...
禁用或抑制消息
假设您想要排除 SC2181 类型的警告,那么您可以在 shell 中执行以下操作:环境变量SHELLCHECK_OPTS 可以设置为默认标志以排除,如下所示。例如,使用导出命令如下:
然后运行:
最后,在脚本本身中添加以下注释以禁用当前行或下一行的警告:
$ shellcheck --exclude=CODE script.sh
$ shellcheck --exclude=CODE1,CODE2 script.sh
$ shellcheck --exclude=SC2124,SC2181 script.sh
$ export SHELLCHECK_OPTS='--exclude=SC2124,SC2181'
$ shellcheck script.sh
# shellcheck disable=CODE if [ -z $foo ]; then ...
但是,开发人员可以在 shell 脚本的顶部添加以下行来影响整个文件,而不仅仅是当前行或下一行。例如:
#!/bin/bash # shellcheck disable=SC2016,SC2086,SC2129,SC2039 ... ...
如何在文本编辑器中集成 shellcheck
您可以直接使用 VIM 或 emacs 文本编辑器进行 shellcheck。我正在使用neomake vim 插件。它是 Neovim/Vim 的异步 linting 和 make 框架。我使用 ~/.vimrc 中的 vim-plug 插件管理器安装了它:
要安装 ansible-vim 和 neomake/neomake,请在 vim 中输入以下命令:
要使用插件,请在编写/编辑 bash/sh 脚本时输入以下命令:
示例输出:
call plug#begin('~/.vim/plugged')
Plug 'pearofducks/ansible-vim'
" install and use neomake linting
Plug 'neomake/neomake'
call plug#end()
:PlugInstall
:Neomake
图 02:Neomake 使用 shellcheck 显示警告/错误
关于处理源命令的注意事项
当您在脚本中使用 source 命令时:
source "lib.sh"
或者
. "lib.sh"
运行 linter 时,您可能会收到以下消息:
Can't follow non-constant source. Use a directive to specify location.
更新您的代码如下:
# shellcheck source=lib.sh source "lib.sh"
或者
# shellcheck source=lib.sh . "lib.sh"
-x然后通过在 CLI 中传递允许 FILES 之外的“源”来测试它:
$ shellcheck -x your-script.sh
结论
总的来说,这是一个用于改进和修复 shell 脚本的出色小工具。它可以检测许多常见错误和失误。有关更多信息,请参阅github页面。请使用 help 命令或 man 命令检查以下手册页:
$ man bash
$ man shellcheck
$ shellcheck --help