Shell coding specification manual (shellcheck error summary)

Shell coding standard manual

background

​ Before the shell script is submitted, it must be scanned with a static code scanning tool shellcheck. Modify the code according to the prompts. After scanning, it can pass without error.

Tool use

​ Install shellcheckand use the command to scan, the specific steps are as follows:

# 安装:
apt install shellcheck
# 扫描:
shellcheck  -x -s bash *.sh
# -s 指定使用 bash
# -x 给予shellcheck跟踪文件的权限,例如一个文件中导入了其他文件

Error number

​ Every error scanned by shellcheck has its number to SC+4位数字form it. Google can search for detailed suggestions. The following is the sorted out part number, which is divided into two parts:

  • Optional modification number: It is normal in some scenarios, and the error does not need to be modified. Just place the file header 配置跳过该检测项and the 说明configuration command# shellcheck disbale=编号
  • Must modify the number: the error that must be modified

Optional modification number:

SC2154
  • 报错:SC2154: quiet_type is referenced but not assigned.
  • Reason: The variable used in the code quiet_typeis referenced but not assigned
  • Solution: align assignment before referencing variables
  • Special case: The test framework should load multiple files. There are associations in the files. Variables that are not assigned to the current file are processed in other files. Gu can take special treatment at this time and skip this check. File header comments:# shellcheck disable=SC2154
SC2034
if [ "$1" = "true" ] && [ "$2" = "true" ]
then 
	r="pass"
else 
	r="fail"
fi
  • 报错:SC2034: r appears unused. Verify use (or export if used externally).

  • Reason: variable r is not used after assignment, because the file is a public method, Gu variable r will not be used in the script

  • Solution: Skip this check in this file, and add a note to the file header:# shellcheck disbale=SC2034

The number must be modified:

SC2162
read -t 8 -p "${tailor_11}""
  • 报错:SC2162:read without -r will mangle backslashes.
  • Reason: By default, Read will interpret backslashes before spaces and newlines, usually you just want to read data, which is what read -r does. Unless there is a good reason not to use -r, you should always use -r (note that read-r will still strip leading and trailing spaces. IFS="" read-r can prevent this.)
  • modify:
read -r -t 8 -p "${tailor_11}""
  • example:
read name
# 输入:\n z
# 输出:n z

read -r name
# 输入:\n z
# 输出:\n z
SC2181
apt install -y iso-tailor
if [ "$?" == "0" ]
then
...
  • 报错:SC2181:Check exit code directly with e.g. ‘if mycmd;’, not indirectly with $?.
  • Reason: sourcedo not follow the variable
  • modify:

if apt install -y iso-tailor;
then
...
SC1090
source "${PWD}/method/config.sh"
  • 报错:SC1090: Can’t follow non-constant source. Use a directive to specify location.
  • Reason: sourcedo not follow the variable
  • modify:
source "method/config.sh"
SC1091
source method/config
  • 报错: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

  • solve:

    • Add parameters to the command line output check command to -xallow shellcheck to trace the file: shellcheck -x -s bash test.sh

      • Note: When the file is not authorized, use the later method
    • Add a comment to the wrong command in the file to # shellcheck disable=SC1091skip the check of the wrong item:

      • # 方法1验证有效
        # 注意:一般在对涉及文件无权限时,使用此方法
        # shellcheck disable=SC1091
        source method/assertion.sh
        
        # 方法2验证无效(why?)
        # 注意:一般在对涉及文件有权限时,使用此方法
        # shellcheck source=method/assertion.sh
        source method/assertion.sh
        
SC2219
  • 报错:SC2219: Instead of ‘let expr’, prefer (( expr )) .

  • Reason: use (( ))insteadlet

  • solve:

    • # 修改前
      let a+=1 
      
      # 修改后
      (( a+=1 ))
      
SC2076
  • 报错:SC2076: Don’t quote rhs of =~, it’ll match literally rather than as a regex.

  • Reason: Use =~but the value on the right side exists " ", it will match literally instead of regular expression

  • solve:

    • # 修改前
      
      # 修改方案1,不使用" ",但该场景是使用传入的值,无法控制,推荐使用方案2
      # 备注:若=~右侧非变量,去掉" "即可,若有空格可使用'\'
      if [[ "${2}" =~ ${1} ]]
      
      # 修改方案2,不使用 '=~'
      if [[ "${2}" == *"${1}"* ]]
      
SC2010
  • 报错:SC2010: Don’t use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.

  • Reason: do not use ls|grep, use glob wildcard

  • solve:

    • #修改前
      iso="$(ls ${
                
                PWD}/resource/test_iso/ | grep iso)"
      
      #修改后
      iso="$(ls ${
                
                PWD}/resource/test_iso/*iso*)"
      
SC2046
  • 报错:Double quote to prevent globbing and word splitting.

  • Reason: When the command is expanded without quotation marks, word splitting and global merging will occur. When the file name contains spaces, this usually manifests as a break.

  • solve:

# 修改前
if [ $(command -v startdde) ];then
	os_type="gui"
else
	os_type="cli"
fi

#修改后
if [ "$(command -v startdde)" ];then
	os_type="gui"
else
	os_type="cli"
fi
SC2086
  • 报错:Double quote to prevent globbing and word splitting.

  • Reason: Quoting variables can prevent word splitting and global expansion, and prevent script interruption when the input contains spaces, line breaks, global characters, etc.

  • solve:

    • # 修改前
      ls ${PWD}/.file
      
      #修改后
      ls "${PWD}/.file"
      
SC2188
  • 报错:SC2188: This redirection doesn’t have a command. Move to its command (or use ‘true’ as no-op).

  • Reason: No command for redirection

  • solve:

    • # 修改前
      > ${error_log_path}
      
      # 修改后
      true > ${error_log_path}
      
SC2013
  • 报错:SC2013: To read lines rather than words, pipe/redirect to a ‘while read’ loop.

  • Reason: To read lines instead of words, use pipe/redirect to while readloop

  • solve:

    • # 修改前
      for case_files in $(cat ${
               
               PWD}/.file/iso_case_list.log);do
      	source ${PWD}/case/iso_case/Round_${case_files}.sh
      done
      
      # 修改后
      while read -r line || [[ -n $line ]]; do
      	source "${PWD}/case/iso_case/Round_${line}.sh"
      done < "${PWD}/.file/iso_case_list.log"
      
SC2129
  • 报错:SC2129:Consider using { cmd1; cmd2; } >> file instead of individual redirects.

  • Reason: For multiple redirections, it is recommended to use {cmd1; cmd2;} >> file, which is more concise

  • solve:

    • # Problematic code:
      
      echo foo >> file
      date >> file
      cat stuff  >> file
      
      # ------------------------
      
      # Correct code:
      
      {
        echo foo
        date
        cat stuff
      } >> fil
      
SC2126
  • 报错:SC2126:Consider using grep -c instead of grep | wc

  • Reason: when grep+wc, grep -c can be used instead

  • solve:

    • # Problematic code:
      grep "${com}" "${error_log_path}" | wc -l
      
      
      # Correct code:
      grep -c "${com}" "${error_log_path}"
      
SC2230
  • 报错:SC2230:which is non-standard. Use builtin ‘command -v’ instead.

  • Reason: which is a non-standard external tool that locates executable files in the PATH. command -v is a POSIX standard built-in command, it uses the same search mechanism as the shell itself, command -vinstead ofwhich

  • solve:

    • # Problematic code:
      which wc
      
      
      # Correct code:
      command -v wc
      
SC2002
  • 报错:SC2002:Useless cat. Consider ‘cmd < file | …’ or ‘cmd file | …’ instead.

  • Reason: It CATis a tool to enable files. Reading a single file as the input of the program is considered a useless use of Cat (UUOC). Simply using redirection is more efficient and less roundabout. This is especially true for programs that can benefit from searchable input (such as Tail or tar).

  • solve:

    • # Problematic code:
      cat file | grep iso
      cat file | wc -l
      
      # Correct code:
      grep iso file
      wc -l < file
      
SC2164
  • Error: SC2164: Use cd… || exit in case cd fails.

  • Reason: It CATis a tool to enable files. Reading a single file as the input of the program is considered a useless use of Cat (UUOC). Simply using redirection is more efficient and less roundabout. This is especially true for programs that can benefit from searchable input (such as Tail or tar).

  • solve:

    • # Problematic code:
      cd generated_files
      rm -r *.c
      
      func(){
              
              
        cd foo
        do_something
      }
      
      
      # Correct code:
      cd generated_files || exit
      rm -r *.c
      
      func(){
              
              
        cd foo || return
        do_something
      }
      
SC2145
  • 报错:SC2145:Argument mixes string and array. Use * or separate argument.

  • Reason: The parameter is a mixture of string and array. Use * or separate parameters.

  • solve:

    • #Problematic code:
      printf "Error: %s\n" "Bad parameters: $@"
      #Correct code:
      printf "Error: %s\n" "Bad parameters: $*"
      
      #Problematic code 2:
      printf "Error: %s\n" "Bad parameters: ${ARRAY_VAR[@]}"
      #Correct code 2:
      printf "Error: %s\n" "Bad parameters: " "${ARRAY_VAR[@]}"
      
SC2185
  • 报错:SC2185:Some finds don’t have a default path. Specify ‘.’ explicitly.

  • Reason: If no search path is provided, GNU and Busybox find will use the default path of the current directory. On POSIX, MacOS/OSX, FreeBSD, OpenBSD, and NetBSD, it can cause errors instead.

  • solve:

    • #Problematic code:
      find |grep test_b_logo
      
      #Correct code:
      find . |grep test_b_logo
      
SC2012
  • 报错:SC2012:Use find instead of ls to better handle non-alphanumeric filenames.

  • Reason: If all you want is file names or their number, then ls can usually be replaced with find.

  • solve:

    • #Problematic code:
      ls case/iso_case/Round*
      
      #Correct code:
      find case/iso_case/Round*
      
      
      # 注意:
      # find输出具有找到的文件的完整路径,相对于运行find的当前工作目录,而ls只有文件名。
      # 所以如果只是项获取文件名,在ls替换find的时候需要做额外的处理
      
SC2143
  • 报错:SC2143:Use grep -q instead of comparing output with [ -n … ].

  • Reason: When grep judges the result, use grep -q instead of outputting the result. The correct code is cleaner and stops at the first matching line, avoiding iterating the rest of the directory and reading the data into memory.

  • solve:

    • #Problematic code:
      if [ "$(find . | grep 'IMG[0-9]')" ]
      then
        echo "Images found"
      fi
      
      #Correct code:
      if find . | grep -q 'IMG[0-9]'
      then
        echo "Images found"
      fi
      
SC2001
  • 报错:SC2001: See if you can use ${variable//search/replace} instead.

  • Reason: When the echo variable + sed is processing the output, the shell tries to use ${variable//search/replace}

  • solve:

    • #Problematic code:
      string="stirng" ; echo "$string" | sed -e "s/ir/ri/"
      
      #Correct code:
      string="stirng" ; echo "${string//ir/ri}"
      
SC2116
  • 报错:SC2116: Useless echo? Instead of ‘cmd $(echo foo)’, just use ‘cmd foo’.

  • Reason: Useless echo

  • solve:

    • #Problematic code:
      greeting=$(echo "Hello, $name")
      # or
      tar czf "$(echo "$(date +%F).tar.gz")" *
      
      #Correct code:
      greeting="Hello, $name"
      # or
      tar czf "$(date +%F).tar.gz" *
      
SC2059
  • 报错:Don’t use variables in the printf format string. Use printf “…%s…” “$foo”.

  • Reason: printfnot used%s

  • solve:

    • #Problematic code:
      printf "Hello, $NAME\n"
      
      #Correct code:
      printf "Hello, %s\n" "$NAME"
      
SC2066
  • 报错:SC2066: Since you double quoted this, it will not word split, and the loop will only run once.

  • Reason: The for loop uses an array: "array[*]". Because of the use of double quotes, the word will not be split, and the loop will only run once.

  • solve:

    • #Problematic code:
      for i in "${test_user_id[*]}";do
      
      #Correct code:
      for i in ${test_user_id[*]};do
      for i in "${test_user_id[@]}";do
      

Guess you like

Origin blog.csdn.net/qq_38123721/article/details/114117300