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 檢查!