ShellCheck 是一个 GPLv3 工具,可为 bash/sh shell 脚本提供警告和建议:
ShellCheck 的目标是
指出并澄清导致 shell 给出神秘错误消息的典型初学者语法问题。
指出并澄清导致 shell 行为奇怪且违反直觉的典型中级语义问题。
指出可能导致高级用户的其他工作脚本在未来情况下失败的微妙警告、极端情况和陷阱。
请参阅不良代码库,了解 ShellCheck 可以帮助您识别的示例!
使用 ShellCheck 有多种方法!
在 https://www.shellcheck.net 上粘贴 shell 脚本以获得即时反馈。
ShellCheck.net 始终同步到最新的 git 提交,并且是尝试 ShellCheck 的最简单方法。告诉你的朋友!
在终端中运行shellcheck yourscript
以获得即时输出,如上所示。
您可以直接在各种编辑器中看到 ShellCheck 建议。
。
。
Sublime,通过 SublimeLinter。
Pulsar Edit(以前的 Atom),通过 linter-shellcheck-pulsar。
VSCode,通过 vscode-shellcheck。
大多数其他编辑器,通过 GCC 错误兼容。
虽然 ShellCheck 主要用于交互式使用,但它可以轻松添加到构建或测试套件中。它规范地使用退出代码,因此您只需添加shellcheck
命令作为该过程的一部分即可。
例如,在 Makefile 中:
check-scripts :
# Fail if any of these files have warnings
shellcheck myscripts/*.sh
或者在 Travis CI .travis.yml
文件中:
script :
# Fail if any of these files have warnings
- shellcheck myscripts/*.sh
已预安装 ShellCheck 并可供使用的服务和平台:
大多数其他服务(包括 GitLab)允许您自行安装 ShellCheck,可以通过系统的包管理器(请参阅安装),也可以通过下载并解压二进制版本来安装。
无论如何,手动安装特定的 ShellCheck 版本是个好主意。这可以避免在发布带有新警告的新版本时出现任何意外的构建中断。
对于自定义过滤或报告,ShellCheck 可以输出简单的 JSON、CheckStyle 兼容的 XML、GCC 兼容的警告以及人类可读的文本(带或不带 ANSI 颜色)。请参阅集成 wiki 页面以获取更多文档。
本地安装 ShellCheck 最简单的方法是通过包管理器。
在带有 Cabal 的系统上(安装到~/.cabal/bin
):
cabal update
cabal install ShellCheck
在带有 Stack 的系统上(安装到~/.local/bin
):
stack update
stack install ShellCheck
在基于 Debian 的发行版上:
sudo apt install shellcheck
在基于 Arch Linux 的发行版上:
pacman -S shellcheck
或者从 AUR 获取无依赖项的 shellcheck-bin。
在基于 Gentoo 的发行版上:
emerge --ask shellcheck
在基于 EPEL 的发行版上:
sudo yum -y install epel-release
sudo yum install ShellCheck
在基于 Fedora 的发行版上:
dnf install ShellCheck
在 FreeBSD 上:
pkg install hs-ShellCheck
在装有 Homebrew 的 macOS (OS X) 上:
brew install shellcheck
或者使用 MacPort:
sudo port install shellcheck
在 OpenBSD 上:
pkg_add shellcheck
在 openSUSE 上
zypper in ShellCheck
或使用 OneClickInstall - https://software.opensuse.org/package/ShellCheck
关于索鲁斯:
eopkg install shellcheck
在 Windows 上(通过 Chocolatey):
C: > choco install shellcheck
或者Windows(通过winget):
C: > winget install --id koalaman.shellcheck
或者 Windows(通过 scoop):
C: > scoop install shellcheck
来自康达锻造:
conda install -c conda-forge shellcheck
来自 Snap 商店:
snap install --channel=edge shellcheck
来自 Docker 中心:
docker run --rm -v " $PWD :/mnt " koalaman/shellcheck:stable myscript
# Or :v0.4.7 for that version, or :latest for daily builds
或者如果您想要扩展更大的基于 Alpine Linux 的映像,请使用koalaman/shellcheck-alpine
。它的工作方式与常规 Alpine 映像完全相同,但预装了 shellcheck。
使用 nix 包管理器:
nix-env -iA nixpkgs.shellcheck
使用 Flox 包管理器
flox install shellcheck
或者,您可以在此处下载最新版本的预编译二进制文件:
或者查看其他版本的 GitHub 版本(包括每日 git 构建的最新元版本)。
目前还没有适用于 Apple Silicon 的官方二进制文件,但可以通过 ShellCheck for Visual Studio Code 获得第三方版本。
发行版软件包已经附带了man
页。如果您从源代码构建,则可以使用以下命令安装它:
pandoc -s -f markdown-smart -t man shellcheck.1.md -o shellcheck.1
sudo mv shellcheck.1 /usr/share/man/man1
要通过预提交运行 ShellCheck,请将挂钩添加到.pre-commit-config.yaml
:
repos:
- repo: https://github.com/koalaman/shellcheck-precommit
rev: v0.7.2
hooks:
- id: shellcheck
# args: ["--severity=warning"] # Optionally only show errors and warnings
Travis CI 现在已经默认集成了 ShellCheck,因此您无需手动安装它。
如果您仍然想这样做以便在闲暇时升级或确保您使用的是最新版本,请按照以下步骤安装二进制版本。
预编译的二进制文件位于tar.xz
文件中。要解压缩它们,请确保安装了xz
。在 Debian/Ubuntu/Mint 上,您可以apt install xz-utils
。在 Redhat/Fedora/CentOS 上, yum -y install xz
。
一个简单的安装程序可能会执行以下操作:
scversion= " stable " # or "v0.4.7", or "latest"
wget -qO- " https://github.com/koalaman/shellcheck/releases/download/ ${scversion?} /shellcheck- ${scversion?} .linux.x86_64.tar.xz " | tar -xJv
cp " shellcheck- ${scversion} /shellcheck " /usr/bin/
shellcheck --version
本节介绍如何从源目录构建 ShellCheck。 ShellCheck 是用 Haskell 编写的,需要 2GB RAM 才能编译。
ShellCheck 是使用 Cabal 构建和打包的。从系统的软件包管理器安装cabal-install
软件包(例如apt-get
、 brew
、 emerge
、 yum
或zypper
)。
在 macOS (OS X) 上,您可以使用 brew 快速安装 Cabal,如果您尝试从源代码编译,则需要几分钟而不是 30 多分钟。
$ brew install cabal-install
在 MacPorts 上,该软件包称为hs-cabal-install
,而本机 Windows 用户应从 https://www.haskell.org/platform/ 安装最新版本的 Haskell 平台
验证cabal
是否已安装并更新其依赖项列表
$ cabal update
git clone
此存储库,然后cd
到 ShellCheck 源目录来构建/安装:
$ cabal install
这将编译 ShellCheck 并将其安装到~/.cabal/bin
目录。
将此目录添加到您的PATH
(对于 bash,将其添加到您的~/.bashrc
):
export PATH= " $HOME /.cabal/bin: $PATH "
注销并再次登录,并验证您的 PATH 设置是否正确:
$ which shellcheck
~ /.cabal/bin/shellcheck
在本机 Windows 上,应该已经设置了PATH
,但系统可能使用旧代码页。在cmd.exe
、 powershell.exe
和 Powershell ISE 中,确保使用 TrueType 字体,而不是 Raster 字体,并使用chcp
将活动代码页设置为 UTF-8 (65001):
chcp 65001
在 Powershell ISE 中,您可能需要另外更新输出编码:
[ Console ]::OutputEncoding = [ System.Text.Encoding ]::UTF8
要运行单元测试套件:
$ cabal test
那么 ShellCheck 会寻找什么样的东西呢?以下是检测到的问题的不完整列表。
ShellCheck 可以识别几种类型的错误引用:
echo $1 # Unquoted variables
find . -name * .ogg # Unquoted find/grep patterns
rm " ~/my file.txt " # Quoted tilde expansion
v= ' --verbose="true" ' ; cmd $v # Literal quotes in variables
for f in " *.ogg " # Incorrectly quoted 'for' loops
touch $@ # Unquoted $@
echo ' Don ' t forget to restart ! ' # Singlequote closed by apostrophe
echo ' Don ' t try this at home ' # Attempting to escape ' in ' '
echo ' Path is $PATH ' # Variables in single quotes
trap " echo Took ${SECONDS} s " 0 # Prematurely expanded trap
unset var[i] # Array index treated as glob
ShellCheck 可以识别多种类型的错误测试语句。
[[ n != 0 ]] # Constant test expressions
[[ -e * .mpg ]] # Existence checks of globs
[[ $foo == 0 ]] # Always true due to missing spaces
[[ -n " $foo " ]] # Always true due to literals
[[ $foo =~ " fo+ " ]] # Quoted regex in =~
[ foo =~ re ] # Unsupported [ ] operators
[ $1 -eq " shellcheck " ] # Numerical comparison of strings
[ $n && $m ] # && in [ .. ]
[ grep -q foo file ] # Command without $(..)
[[ " $$ file " == * .jpg ]] # Comparisons that can't succeed
(( 1 - lt 2 )) # Using test operators in ((..))
[ x ] & [ y ] | [ z ] # Accidental backgrounding and piping
ShellCheck 可以识别命令使用不正确的情况:
grep ' *foo* ' file # Globs in regex contexts
find . -exec foo {} && bar {} ; # Prematurely terminated find -exec
sudo echo ' Var=42 ' > /etc/profile # Redirecting sudo
time --format=%s sleep 10 # Passing time(1) flags to time builtin
while read h ; do ssh " $h " uptime # Commands eating while loop input
alias archive= ' mv $1 /backup ' # Defining aliases with arguments
tr -cd ' [a-zA-Z0-9] ' # [] around ranges in tr
exec foo ; echo " Done! " # Misused 'exec'
find -name * .bak -o -name * ~ -delete # Implicit precedence in find
# find . -exec foo > bar ; # Redirections in find
f () { whoami ; }; sudo f # External use of internal functions
ShellCheck 可以识别初学者的许多常见语法错误:
var = 42 # Spaces around = in assignments
$foo =42 # $ in assignments
for $var in * ; do ... # $ in for loop variables
var $n = " Hello " # Wrong indirect assignment
echo ${var $n } # Wrong indirect reference
var=(1, 2, 3) # Comma separated arrays
array=( [index] = value ) # Incorrect index initialization
echo $var [14] # Missing {} in array references
echo " Argument 10 is $1 0 " # Positional parameter misreference
if $( myfunction ) ; then .. ; fi # Wrapping commands in $()
else if othercondition ; then .. # Using 'else if'
f ; f () { echo " hello world; } # Using function before definition
[ false ] # 'false' being true
if ( -f file ) # Using (..) instead of test
ShellCheck可以提出改进风格的建议:
[[ -z $( find /tmp | grep mpg ) ]] # Use grep -q instead
a >> log ; b >> log ; c >> log # Use a redirection block instead
echo " The time is ` date ` " # Use $() instead
cd dir ; process * ; cd .. ; # Use subshells instead
echo $[1+2] # Use standard $((..)) instead of old $[]
echo $(( $RANDOM % 6 )) # Don't use $ on variables in $((..))
echo " $( date ) " # Useless use of echo
cat file | grep foo # Useless use of cat
ShellCheck 可以识别与数据和输入相关的问题:
args= " $@ " # Assigning arrays to strings
files=(foo bar) ; echo " $files " # Referencing arrays as strings
declare -A arr=(foo bar) # Associative arrays without index
printf " %sn " " Arguments: $@ . " # Concatenating strings and arrays
[[ $# > 2 ]] # Comparing numbers as strings
var=World ; echo " Hello " var # Unused lowercase variables
echo " Hello $name " # Unassigned lowercase variables
cmd | read bar ; echo $bar # Assignments in subshells
cat foo | cp bar # Piping to commands that don't read
printf ' %s: %sn ' foo # Mismatches in printf argument count
eval " ${array[@]} " # Lost word boundaries in array eval
for i in " ${x[@]} " ; do ${x[$i]} # Using array value as key
ShellCheck 可以提出提高脚本稳健性的建议:
rm -rf " $STEAMROOT / " * # Catastrophic rm
touch ./-l ; ls * # Globs that could become options
find . -exec sh -c ' a && b {} ' ; # Find -exec shell injection
printf " Hello $name " # Variables in printf format
for f in $( ls * .txt ) ; do # Iterating over ls output
export MYVAR= $( cmd ) # Masked exit codes
case $version in 2. * ) : ;; 2.6. * ) # Shadowed case branches
当使用 shebang 不支持的功能时,ShellCheck 会发出警告。例如,如果将 shebang 设置为#!/bin/sh
,ShellCheck 将警告类似于checkbashisms
可移植性问题:
echo {1.. $n } # Works in ksh, but not bash/dash/sh
echo {1..10} # Works in ksh and bash, but not dash/sh
echo -n 42 # Works in ksh, bash and dash, undefined in sh
expr match str regex # Unportable alias for `expr str : regex`
trap ' exit 42 ' sigint # Unportable signal spec
cmd & > file # Unportable redirection operator
read foo < /dev/tcp/host/22 # Unportable intercepted files
foo-bar () { .. ; } # Undefined/unsupported function name
[ $UID = 0 ] # Variable undefined in dash/sh
local var=value # local is undefined in sh
time sleep 1 | sleep 5 # Undefined uses of 'time'
ShellCheck 还可以识别一系列其他问题:
PS1= ' e[0;32m$e[0m ' # PS1 colors not in [..]
PATH= " $PATH :~/bin " # Literal tilde in $PATH
rm “file” # Unicode quotes
echo " Hello world " # Carriage return / DOS line endings
echo hello # Trailing spaces after
var=42 echo $var # Expansion of inlined environment
! # bin/bash -x -e # Common shebang errors
echo $(( n / 180 * 100 )) # Unnecessary loss of precision
ls * [:digit:].txt # Bad character class globs
sed ' s/foo/bar/ ' file > file # Redirecting to input
var2= $var2 # Variable assigned to itself
[ x $var = xval ] # Antiquated x-comparisons
ls () { ls -l " $@ " ; } # Infinitely recursive wrapper
alias ls= ' ls -l ' ; ls foo # Alias used before it takes effect
for x ; do for x ; do # Nested loop uses same variable
while getopts " a " f ; do case $f in " b " ) # Unhandled getopts flags
一开始你会想“shellcheck 太棒了”,但后来你会想“天哪,我们还在使用 bash 吗”
亚历山大·塔拉西科夫,来自 Twitter
可以通过环境变量、命令行、文件中单独或全局忽略问题:
https://github.com/koalaman/shellcheck/wiki/Ignore
请使用 GitHub 问题跟踪器来获取任何错误或功能建议:
https://github.com/koalaman/shellcheck/issues
请以 GitHub 拉取请求的形式提交代码或文档补丁!查看 ShellCheck Wiki 上的 DevGuide。
贡献必须根据 GNU GPLv3 获得许可。贡献者保留版权。
ShellCheck 根据 GNU 通用公共许可证 v3 获得许可。该许可证的副本包含在 LICENSE 文件中。
版权所有 2012-2019,Vidar 'koala_man' Holen 和贡献者。
快乐的 Shell 检查!