shellcheck 幫助你寫出更好的指令碼
簡介
shellcheck 是一款實用的 shell指令碼靜態檢查工具。
首先,可以幫助你提前發現並修復簡單的語法錯誤,節約時間。每次都需要執行才發現寫錯了一個小地方,確實非常浪費時間。
其次,可以針對你當前不夠完善不夠健壯的寫法,提供建議,幫助你提前繞開一些坑,避免等問題真的發生了才去除錯處理。
在其介紹中,目標是針對所有使用者的,從初學者到高手,都用得上
- 指出並澄清典型的初學者的語法問題,那通常會shell提供神祕的錯誤訊息。
- 指出並澄清典型的中級的語義問題,這些問題會導致shell出現奇怪且反直覺的行為。
- 指出可能導致高階使用者的指令碼中,可能在未來某種情況下失敗的陷阱。
如何使用
在網頁上使用
非常簡單,在網頁 https://www.shellcheck.net 上,貼入你的指令碼,執行檢查即可
在命令列中使用
下載後,在命令列中呼叫 shellcheck yourscript 即可
整合到編輯器中(推薦)
推薦將shellcheck直接整合到日常編輯器中,這樣就可以直接在編輯器中檢視ShellCheck建議,以最快速度發現並修復問題。
- Vim 通過 ALE, Neomake 或 Syntastic 進行整合
- Emacs 通過 Flycheck 或 Flymake 整合
- Sublime 通過 SublimeLinter.
- Atom 通過 Linter.
- VSCode 通過 vscode-shellcheck.
安裝方式
在大多數發行版的包管理中,已經有shellcheck了,如在基於debian的機器上
apt-get install shellcheck
其他系統的具體安裝方式,可以查閱 shellcheck 的github首頁介紹
當然,也可以選擇自行從原始碼安裝。
問題列表
那麼shellcheck具體會檢查一些什麼問題呢,以下給出一個不完整的問題檢查列表。
可以看下,你是否都能意識到這樣的寫法時有錯誤或隱患的。
如果發現有自己不知道的或自己容易錯漏的,那麼也許你也應該花點時間,裝上shellcheck。
引號問題
echo $1# Unquoted variables#變數未加引號 find . -name *.ogg# Unquoted find/grep patterns #find/grep 的匹配模式未加引號 rm "~/my file.txt"# Quoted tilde expansion #引號中的波浪符擴充套件 v='--verbose="true"'; cmd $v# Literal quotes in variables # 變數中的字面引號 for f in "*.ogg"# Incorrectly quoted 'for' loops # 錯誤的for迴圈 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 #過早擴充套件陷阱
條件判斷
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 ((..)) #在((..))中使用比較
常見的對命令的錯誤使用
ShellCheck 可以識別對一些命令的錯誤使用
grep '*foo*' file# Globs in regex contexts#在grep的正則表示式中前後使用萬用字元 find . -exec foo {} && bar {} \;# Prematurely terminated find -exec# 使find -exec 過早結束 sudo echo 'Var=42' > /etc/profile # Redirecting sudo # 重定向sudo time --format=%s sleep 10# Passing time(1) flags to time builtin # 將time(1)的標誌傳遞給內建的time while read h; do ssh "$h" uptime# Commands eating while loop input# 一個獲取輸入的while迴圈中,使用同樣會獲取輸入的命令 alias archive='mv $1 /backup'# Defining aliases with arguments # 定義使用引數的alias tr -cd '[a-zA-Z0-9]'# [] around ranges in tr # 在tr的引數範圍外使用[] exec foo; echo "Done!"# Misused 'exec'# 錯誤地使用exec find -name \*.bak -o -name \*~ -delete# Implicit precedence in find# 在find中的隱式優先順序 # find . -exec foo > bar \;# Redirections in find#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 $10"# Positional parameter misreference #錯誤的位置引數引用 if $(myfunction); then ..; fi# Wrapping commands in $() #在命令外加上$() else if othercondition; then ..# Using 'else if'#使用else if f; f() { echo "hello world; }# Using function before definition 在函式定義之前使用函式 [ false ]# 'false' being true # 此處false為true if ( -f file )# Using (..) instead of test #使用()取代測試條件
風格
ShellCheck 可以提出一些風格改進建議
[[ -z $(find /tmp | grep mpg) ]]# Use grep -q instead#改成使用grep -q 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#改成使用subshell echo $[1+2]# Use standard $((..)) instead of old $[]#改成使用標準的$((..)) echo $(($RANDOM % 6))# Don't use $ on variables in $((..)) #在$((..))中不要使用$ echo "$(date)"# Useless use of echo # 沒必要的echo cat file | grep foo# Useless use of cat #沒必要的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 "%s\n" "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 # 在subshells中進行賦值 cat foo | cp bar# Piping to commands that don't read # 通過管道傳遞資料給一個不會做讀取的程式 printf '%s: %s\n' foo# Mismatches in printf argument count # pirintf引數數量不匹配
魯棒性
ShellCheck可以做出一些增強指令碼魯棒性的建議
rm -rf "$STEAMROOT/"*# Catastrophic rm # 可能導致災難性後果的rm touch ./-l; ls *# Globs that could become options # 使用了可能變成選項的萬用字元 find . -exec sh -c 'a && b {}' \; # Find -exec shell injection # Find -exec shell注入 printf "Hello $name"# Variables in printf format # 在printf的格式化引數中使用變數 for f in $(ls *.txt); do# Iterating over ls output # 在ls的輸出上進行迭代 export MYVAR=$(cmd)# Masked exit codes # 使退出碼模糊 case $version in 2.*) :;; 2.6.*) # Shadowed case branches # 隱蔽的case分支
可移植性
ShellCheck 警告你使用了 shebang 不支援的特性.。
比如,當你設定 shebang 為#!/bin/sh
是, ShellCheck 對類似checkbashisms
的可移植性問題發出警告。
echo {1..$n}# Works in ksh, but not bash/dash/sh#在 ksh 中可用,在 bash/dash/sh 中不可用 echo {1..10}# Works in ksh and bash, but not dash/sh #在 ksh 中可用,在 bash/dash/sh 中不可用 echo -n 42# Works in ksh, bash and dash, undefined in sh #在 ksh/bash/dash 中可用,在 sh 中不可用 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 # dash/sh 中未定義的變數 local var=value# local is undefined in sh # sh 中未定義local time sleep 1 | sleep 5# Undefined uses of 'time' # 使用了time未定義的用法
其他雜七雜八的問題
ShellCheck 可以識別到一些其他問題
PS1='\e[0;32m\$\e[0m '# PS1 colors not in \[..\]# PS1 的顏色不在\[..\] 中 PATH="$PATH:~/bin"# Literal tilde in $PATH # $PATH中的波浪號 rm “file”# Unicode quotes #Unicode 引號 echo "Hello world"# Carriage return / DOS line endings # 傳輸返回DOS行結束符/ echo hello \# Trailing spaces after \# \後面的行尾空格 var=42 echo $var# Expansion of inlined environment # 展開內聯環境變數 #!/bin/bash -x -e# Common shebang errors # shebang命令錯誤 echo $((n/180*100))# Unnecessary loss of precision # 不必要的精度丟失 ls *[:digit:].txt# Bad character class globs # 不好的萬用字元 sed 's/foo/bar/' file > file# Redirecting to input # 重定向到輸入 while getopts "a" f; do case $f in "b") # Unhandled getopts flags # 未處理的getopts標誌
總結
以上就是shellcheck的介紹了,主要來自其github 的readme ,原始碼在ofollow,noindex" target="_blank">github https://github.comf/koalaman/shellcheck
簡單實用,只要配置好了,就可以持續為你提供幫助。而且這個是建議性的,可以自己根據實際情況決定是否採納。即用即棄的臨時指令碼,那相容性等就不用太care。長期使用的,就還是完善一下比較穩妥。
本文地址 https://www.cnblogs.com/zqb-all/p/10054594.html