简介

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 ,源码在 github https://github.comf/koalaman/shellcheck

简单实用,只要配置好了,就可以持续为你提供帮助。而且这个是建议性的,可以自己根据实际情况决定是否采纳。即用即弃的临时脚本,那兼容性等就不用太care。长期使用的,就还是完善一下比较稳妥。

本文地址 https://www.cnblogs.com/zqb-all/p/10054594.html

shellcheck 帮助你写出更好的脚本的更多相关文章

  1. 使用Groovy+Spock轻松写出更简洁的单测

    当无法避免做一件事时,那就让它变得更简单. 概述 单测是规范的软件开发流程中的必不可少的环节之一.再伟大的程序员也难以避免自己不犯错,不写出有BUG的程序.单测就是用来检测BUG的.Java阵营中,J ...

  2. [label][翻译][JavaScript-Translation]七个步骤让你写出更好的JavaScript代码

    7 steps to better JavaScript 原文链接: http://www.creativebloq.com/netmag/7-steps-better-javascript-5141 ...

  3. 如何在 ASP.NET Core 中写出更干净的 Controller

    你可以遵循一些最佳实践来写出更干净的 Controller,一般我们称这种方法写出来的 Controller 为瘦Controller,瘦 Controller 的好处在于拥有更少的代码,更加单一的职 ...

  4. 写出更好的 JavaScript 条件语句

    1. 使用 Array.includes 来处理多重条件 // 条件语句 function test(fruit) { if (fruit == 'apple' || fruit == 'strawb ...

  5. 让我们一起写出更有效的CSharp代码吧,少年们!

    周末空闲,选读了一下一本很不错的C#语言使用的书,特此记载下便于对项目代码进行重构和优化时查看. Standing On Shoulders of Giants,附上思维导图,其中标记的颜色越深表示在 ...

  6. Java 11正式发布,这几个逆天新特性教你写出更牛逼的代码

    就在前段时间,Oracle 官方宣布 Java 11 (18.9 LTS) 正式发布,可在生产环境中使用! 这无疑对我们来说是一大好的消息.作为一名java开发者来说,虽然又要去学习和了解java11 ...

  7. 在用 JavaScript 工作时,我们经常和条件语句打交道,这里有5条让你写出更好/干净的条件语句的建议。

    1.多重判断时使用 Array.includes 2.更少的嵌套,尽早 return 3.使用默认参数和解构 4.倾向于遍历对象而不是 Switch 语句 5.对 所有/部分 判断使用 Array.e ...

  8. 9条消除if...else的锦囊妙计,助你写出更优雅的代码

    前言 最近在做代码重构,发现了很多代码的烂味道.其他的不多说,今天主要说说那些又臭又长的if...else要如何重构. 在介绍更更优雅的编程之前,让我们一起回顾一下,不好的if...else代码 一. ...

  9. Java 11 正式发布,这 8 个逆天新特性教你写出更牛逼的代码

    美国时间 09 月 25 日,Oralce 正式发布了 Java 11,这是据 Java 8 以后支持的首个长期版本. 为什么说是长期版本,看下面的官方发布的支持路线图表. 可以看出 Java 8 扩 ...

随机推荐

  1. Spring MVC之@RequestBody@ResponseBody详解

    引言: 接上一篇文章讲述处理@RequestMapping的方法参数绑定之后,详细介绍下@RequestBody.@ResponseBody的具体用法和使用时机: 简介: @RequestBody 作 ...

  2. 【bzoj4720】[NOIP2016]换教室 期望dp

    题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程.在可以选择的课程中,有2n节课程安排在n个时间段上.在第i(1≤i≤n)个时间段上,两节内容相同的课程同时在不同的 ...

  3. javascript标准对象与包装对象

    javascript标准对象与包装对象 标准对象 在JavaScript的世界里,一切都是对象. 但是某些对象还是和其他对象不太一样.为了区分对象的类型,我们用typeof操作符获取对象的类型,它总是 ...

  4. Retrofit工具类

    package com.example.week2.retrofitUtils; import android.util.Log; import com.example.week2.model.Con ...

  5. BZOJ3781:小B的询问——题解

    https://www.luogu.org/problemnew/show/2709 http://www.lydsy.com/JudgeOnline/problem.php?id=3781 题目描述 ...

  6. 洛谷3805:【模板】manacher算法——题解

    https://www.luogu.org/problemnew/show/P3805 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 字符串长度为n 板子题, ...

  7. BZOJ4245 [ONTAK2015]OR-XOR 【贪心】

    题目链接 BZOJ4245 题解 套路① 位运算当然要分位讨论,高位优先 考虑在\(or\)下,如果该位为\(0\),则每一位都为\(0\) 套路② 我们选m段异或和,转化为\(m\)个前缀和的点,且 ...

  8. 【简单算法】17.字符串转整数(atoi)

    题目: 实现 atoi,将字符串转为整数. 在找到第一个非空字符之前,需要移除掉字符串中的空格字符.如果第一个非空字符是正号或负号,选取该符号,并将其与后面尽可能多的连续的数字组合起来,这部分字符即为 ...

  9. JavaScript时间戳与其格式化

    在 PHP + MySQL (日期类型为datetime) + ajax 应用中,有时候需要用 JavaScript 将时间戳类型格式化为一般的时间类型格式.下面提供一些转换的方法,比较常见的一些总结 ...

  10. HDU 3507 斜率优化dp

    Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)To ...