Shell 脚本提交以前必须用静态代码扫描工具 shellcheck
扫描,根据提示修改代码,需达到扫描后无报错即可通过。
修改过程中整理了一些常见错误与解决办法以供参考。
安装 shellcheck
并使用命令进行扫描,具体步骤如下:
shellcheck
扫描出的每一个错误,均有其编号,以 SC+4位数字
组成,google 可搜索到详细建议,以下为整理出的部分编号,分为两部分:
可选修改编号:部分场景下为正常现象,该错误无需修改,在文件头配置跳过该检测项
与说明
即可,配置命令 # shellcheck disbale=编号
必须修改编号:必须修改的错误
quiet_type
被引用,但并未被赋值# shellcheck disable=SC2154
报错:SC2034: r appears unused. Verify use (or export if used externally).
原因:变量r赋值后未被使用,因该文件是存放公共方法,顾变量r在脚本中不会被使用
解决:在此文件跳过该项检查,文件头增加注释:# shellcheck disbale=SC2034
if mycmd;
,而不是使用$?source
后不要跟变量报错:SC1091: Not following: method/config was not specified as input (see shellcheck -x).
原因:file not found, no permissions, not included on the command line, not allowing shellcheck
to follow files with -x
解决:
命令行输出检查命令时加上参数-x
,允许 shellcheck 跟踪文件:shellcheck -x -s bash test.sh
文件中错误命令上增加注释# shellcheck disable=SC1091
,跳过该错误项检查:
报错:SC2219: Instead of 'let expr', prefer (( expr )) .
原因:使用(( ))
代替 let
解决:
报错:SC2076: Don't quote rhs of =~, it'll match literally rather than as a regex.
原因:使用=~
但右侧的值存在" "
,那将按照字面量匹配,而非正则表达式
解决:
报错:SC2010: Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
原因:不要使用 ls|grep,可使用 glob 通配符
解决:
报错:Double quote to prevent globbing and word splitting.
原因:当命令扩展未加引号时,将发生单词拆分和全局合并。当文件名包含空格时,这通常表现为中断。
解决:
报错:Double quote to prevent globbing and word splitting.
原因:引用变量可防止单词拆分和全局扩展,并在输入包含空格、换行符、全局字符等时防止脚本中断。
解决:
报错:SC2188: This redirection doesn't have a command. Move to its command (or use 'true' as no-op).
原因:重定向无命令
解决:
报错:SC2013: To read lines rather than words, pipe/redirect to a 'while read' loop.
原因:要读取行,而不是词时,使用管道/重定向到while read
循环
解决:
报错:SC2129:Consider using { cmd1; cmd2; } >> file instead of individual redirects.
原因:多个重定向时,建议使用{ cmd1; cmd2; } >> file,更为简洁
解决:
SC2126
报错:SC2126:Consider using grep -c
instead of grep | wc
原因:grep+wc时,可使用grep -c代替
解决:
报错:SC2230:which is non-standard. Use builtin 'command -v' instead.
原因:which是在PATH中定位可执行文件的非标准外部工具。command -v是一个POSIX标准内置命令,它使用与shell本身相同的查找机制,使用command -v
代替which
解决:
报错:SC2002:Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.
原因:CAT
是启用文件的工具。将单个文件作为程序的输入读取被认为是对Cat(UUOC)的无用使用。简单地使用重定向更高效、更少迂回。对于可以从可查找的输入中获益的程序(如Tail或tar),情况尤其如此。
解决:
报错:SC2164:Use cd ... || exit in case cd fails.
原因:CAT
是启用文件的工具。将单个文件作为程序的输入读取被认为是对Cat(UUOC)的无用使用。简单地使用重定向更高效、更少迂回。对于可以从可查找的输入中获益的程序(如Tail或tar),情况尤其如此。
解决:
报错:SC2145:Argument mixes string and array. Use * or separate argument.
原因:参数混合了字符串和数组。使用*或单独的参数。
解决:
报错:SC2185:Some finds don't have a default path. Specify '.' explicitly.
原因:如果没有提供搜索路径,GNU和Busybox find将使用当前目录的默认路径。在POSIX、MacOS/OSX、FreeBSD、OpenBSD和NetBSD上,它反而会导致错误。
解决:
报错:SC2012:Use find
instead of ls
to better handle non-alphanumeric filenames.
原因:如果您想要的仅仅是文件名或它们的数量,那么ls通常可以替换为find。
解决:
报错:SC2143:Use grep -q instead of comparing output with [ -n .. ].
原因:grep判断结果时,使用grep -q,而不是将结果输出,正确的代码更干净,并在第一个匹配行停止,避免了迭代目录的其余部分和将数据读入内存。
解决:
报错:SC2001: See if you can use ${variable//search/replace} instead.
原因:echo 变量+sed处理输出时,壳尝试使用${variable//search/replace}
解决:
报错:SC2116: Useless echo? Instead of 'cmd $(echo foo)', just use 'cmd foo'.
原因:无用的echo
解决:
报错:Don't use variables in the printf format string. Use printf "..%s.." "$foo".
原因:printf
未使用%s
解决:
报错:SC2066: Since you double quoted this, it will not word split, and the loop will only run once.
原因:for循环使用了数组:"array[*]",由于使用了双引号,因此不会拆分单词,循环只会运行一次。
解决:
报错:SC2103: Use a ( subshell ) to avoid having to cd back..
原因:使用子shell执行命令,避免回放cd。
解决:
报错:SC2103: Use ./glob or -- glob so names with dashes won't become options.
原因:因为文件和参数是以相同方式传递的字符串,所以程序不能正确地识别,使用./
、--
可避免这个问题。
解决:
报错:SC2124: Assigning an array to a string! Assign as array, or use * instead of @ to concatenate.
原因:将数组赋给字符串!赋值为数组,或使用*而不是@进行连接。
解决:
报错:SC1012: \t
is just literal t
here. For tab, use "$(printf '\t')"
instead.
原因:ShellCheck 发现了一个\t
,\n
或者\r
在一个上下文中,它们只是变成了普通的字母t
,n
或者r
。很可能,它被用作制表符、换行符或回车符。
解决:
报错:SC2048: Use "$@" (with quotes) to prevent whitespace problems.
原因:当一个数组使用 for
循环遍历时,相对于 $*
, "$@"
要更为安全,避免空格可引起的其他问题。
解决:
报错:SC2268 (style): Avoid x-prefix in comparisons as it no longer serves a purpose.
原因:避免在比较中使用x-prefix,因为它不再起作用。
解决: