前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【SRE该掌握的利器】提升Shell脚本质量的利器:ShellCheck

【SRE该掌握的利器】提升Shell脚本质量的利器:ShellCheck

原创
作者头像
五分钟学SRE
发布2024-04-26 00:01:29
1450
发布2024-04-26 00:01:29
举报
文章被收录于专栏:五分钟学SRE五分钟学SRE

在Linux系统中,Shell脚本是实现自动化任务的关键工具,对于提高工作效率具有重要意义。然而,编写无误且高效的Shell脚本对于新手来说是一个挑战,因为很容易忽视一些常见的错误和漏洞。幸运的是,ShellCheck作为一个静态分析工具,能够帮助我们发现并改进这些问题。

图片
图片

ShellCheck简介

????ShellCheck是一个开源的静态分析工具,专门用于分析Shell脚本。它能够自动检测出脚本中的多种问题,包括但不限于语法错误、逻辑漏洞、代码风格问题,以及可能的安全风险。ShellCheck不仅能够识别问题,还能提供改进建议,帮助SRE快速定位并修复这些问题。

ShellCheck的安装指南

????ShellCheck支持多种安装方式,包括使用包管理器、源代码编译,以及Docker容器。对于大多数Linux发行版,通过包管理器安装是最简便的方法。以Ubuntu为例,安装ShellCheck的命令如下:

代码语言:javascript
复制
sudo apt-get update
sudo apt-get install shellcheck

????安装后,只需在命令行输入shellcheck即可启动工具。为了提高使用便利性,可以将ShellCheck添加到环境变量中,或配置为代码编辑器的插件。

编辑器中集成 ShellCheck

????ShellCheck 的集成对于提高开发效率和代码质量至关重要。不同编辑器中集成 ShellCheck 的指南:

Vim

在 Vim 中,有几种插件可以帮助集成 ShellCheck:

  • ALE (Asynchronous Lint Engine):提供异步的语法和代码检查。
  • Neomake:一个使用多种语言的异步构建系统和静态分析工具的聚合器。
  • Syntastic:另一个为多种语言提供语法检查的插件。

Emacs

对于 Emacs 用户,以下是集成 ShellCheck 的选项:

  • Flycheck:一个用于 Emacs 的现代语法检查器。
  • Flymake:一个传统的 Emacs 插件,用于实时语法检查。

Sublime Text

在 Sublime Text 中,可以使用 SublimeLinter 插件来集成 ShellCheck,它是一个强大的代码检查框架。

Atom

Atom 编辑器可以通过 Linter 插件来集成 ShellCheck,该插件支持多种语言的语法检查。

VSCode

对于 Visual Studio Code 用户,可以安装 vscode-shellcheck 扩展来集成 ShellCheck,它将提供内联的语法和代码检查。

????通过将 ShellCheck 集成到我们的编辑器,我们可以在编写 shell 脚本时即时获得反馈,这样可以更快地发现并修复潜在的问题,从而提高我们的开发效率和代码质量。

使用ShellCheck的实践

让我们通过一个具体的案例来展示ShellCheck的实际应用。假设我们有以下的Shell脚本示例:

代码语言:javascript
复制
#!/bin/bash

echo "Enter a number:"
read num

if [ $num -gt 10 ]; then
 ? ?echo "Number is greater than 10"
else
 ? ?echo "Number is not greater than 10"
fi

????当我们使用ShellCheck检查这个脚本时,它会发现一个常见的问题:在测试表达式中,[] 之间不应该有空格,否则会导致逻辑错误。ShellCheck会输出如下的警告信息:

代码语言:javascript
复制
shellcheck test.sh 

In test.sh line 4:
read num
^--^ SC2162 (info): read without -r will mangle backslashes.


In test.sh line 6:
if [ $num -gt 10 ]; then
 ? ? ^--^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean: 
if [ "$num" -gt 10 ]; then

For more information:
  https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
  https://www.shellcheck.net/wiki/SC2162 -- read without -r will mangle backs...

????通过这个简单的例子,我们可以看到ShellCheck如何帮助SRE快速定位问题并进行修复。

常见问题

????ShellCheck 是一个用于 shell 脚本的静态分析工具,它能够检查和报告多种常见的问题,帮助SRE提高脚本的质量和安全性。以下是 ShellCheck 能够识别的一些问题的分类列表:

引用

ShellCheck 可以识别几种类型的错误引用:

代码语言:javascript
复制
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 可以识别多种类型的错误测试语句。

代码语言:javascript
复制
[[ 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 可以识别命令使用不正确的情况:

代码语言:javascript
复制
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 # 重定向sudotime --format=%s sleep 10         # Passing time(1) flags to time builtin # 将time(1)的标志传递给内建的timewhile read h; do ssh "$h" uptime  # Commands eating while loop input  # 一个获取输入的while循环中,使用同样会获取输入的命令alias archive='mv $1 /backup'     # Defining aliases with arguments # 定义使用参数的aliastr -cd '[a-zA-Z0-9]'              # [] around ranges in tr # 在tr的参数范围外使用[]exec foo; echo "Done!"            # Misused 'exec'  # 错误地使用execfind -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 可以识别初学者的许多常见语法错误:

代码语言:javascript
复制
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 iff; f() { echo "hello world; }     # Using function before definition 在函数定义之前使用函数[ false ]                         # 'false' being true # 此处false为trueif ( -f file )                    # Using (..) instead of test #使用()取代测试条件

风格

ShellCheck可以提出改进风格的建议:

代码语言:javascript
复制
[[ -z $(find /tmp | grep mpg) ]]  # Use grep -q instead  #改成使用grep -qa >> log; b >> log; c >> log      # Use a redirection block instead #改成使用重定向块echo "The time is `date`"         # Use $() instead #改成使用$()cd dir; process *; cd ..;         # Use subshells instead   #改成使用subshellecho $[1+2]                       # Use standard $((..)) instead of old $[]  #改成使用标准的$((..))echo $(($RANDOM % 6))             # Don't use $ on variables in $((..)) #在$((..))中不要使用$echo "$(date)"                    # Useless use of echo # 没必要的echocat file | grep foo               # Useless use of cat #没必要的cat

数据和打字错误

ShellCheck 可以识别与数据和输入相关的问题:

代码语言:javascript
复制
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 可以提出提高脚本稳健性的建议:

代码语言:javascript
复制
rm -rf "$STEAMROOT/"*            # Catastrophic rm # 可能导致灾难性后果的rmtouch ./-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分支

可移植性

当使用 shebang 不支持的功能时,ShellCheck 会发出警告。例如,如果将 shebang 设置为#!/bin/sh,ShellCheck 将警告类似于以下内容的可移植性问题checkbashisms

代码语言:javascript
复制
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, ?developer/article/2412798/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 ?developer/article/2412798/undefined in dash/sh # dash/sh 中未定义的变量local var=value                  # local is ?developer/article/2412798/undefined in sh # sh 中未定义localtime sleep 1 | sleep 5           # Undefined uses of 'time' # 使用了time未定义的用法

各种各样的

ShellCheck 还可以识别一系列其他问题:

代码语言:javascript
复制
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的优势

????ShellCheck因其强大的功能和用户友好的操作界面,已经成为广大SRE不可或缺的工具之一。它极大地简化了代码审查过程,提高了代码的可维护性和安全性。随着技术的进步,ShellCheck有望增加更多功能,支持更广泛的Shell特性和语法,为SRE提供更全面的代码检查服务。

ShellCheck官网文档:https://www.shellcheck.net/

ShellCheck在GitHub上的项目页面:https://github.com/koalaman/shellcheck

我正在参与2024腾讯技术创作特训营最新征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ShellCheck简介
  • ShellCheck的安装指南
  • 编辑器中集成 ShellCheck
    • Vim
      • Emacs
        • Sublime Text
          • Atom
            • VSCode
              • 引用
              • 条件句
              • 经常被误用的命令
              • 初学者常见的错误
              • 风格
              • 数据和打字错误
              • 鲁棒性
              • 可移植性
              • 各种各样的
          • 使用ShellCheck的实践
          • 常见问题
          • ShellCheck的优势
          相关产品与服务
          腾讯云代码分析
          腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
          http://www.vxiaotou.com