CLOVER🍀

That was when it all began.

Ubuntu Linux 20.04 LTSにShellCheckをインストールする

これは、なにをしたくて書いたもの?

タイトル通り。
シェルスクリプトの静的解析ツールである、ShellCheckをUbuntu Linux 20.04 LTSにインストールしてみます。

ShellCheck

ShellCheckとは、シェルスクリプトの静的解析ツールです。

ShellCheck – shell script analysis tool

GitHub - koalaman/shellcheck: ShellCheck, a static analysis tool for shell scripts

現時点での最新バージョンは、0.9.0です。

オンラインでも使えるようで、ランダムなサンプルからどういうものか確認することができます。

利用形態としては、オンライン(Web)、CLI、エディターとのインテグレーション、CIとのインテグレーションといった感じですね。

ShellCheck / How to use

チェック内容は、このあたりに書かれています。

ShellCheck / Gallery of bad code

ドキュメントは、GitHub Wikiになります。

Home · koalaman/shellcheck Wiki · GitHub

チェック内容の完全な内容も、Wikiにあるようです。

Checks · koalaman/shellcheck Wiki · GitHub

一覧そのものを見るには、こちらからたどるか、GitHub Wikiのページを展開するしかなさそうです。

Enumerated shellcheck codes https://github.com/koalaman/shellcheck/wiki/Checks · GitHub

チェック内容それぞれにページがあります。

SC1000 · koalaman/shellcheck Wiki · GitHub

では、簡単に試してみましょう。

環境

今回の環境は、こちら。Ubuntu Linux 20.04 LTSです。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.5 LTS
Release:        20.04
Codename:       focal


$ uname -srvmpoi
Linux 5.4.0-135-generic #152-Ubuntu SMP Wed Nov 23 20:19:22 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

ShellCheckをインストールする

まずは、ShellCheckをインストールしましょう。

ShellCheck / Installing

Debianベースのディストリビューションの場合は、aptでインストールできるみたいです。

$ sudo apt install shellcheck

確認。

$ shellcheck --version
ShellCheck - shell script analysis tool
version: 0.7.0
license: GNU General Public License, version 3
website: https://www.shellcheck.net

インストールされたのは、0.7.0ですね。少し古いみたいです。

ヘルプを確認。

$ shellcheck --help
Usage: shellcheck [OPTIONS...] FILES...
  -a                  --check-sourced            Include warnings from sourced files
  -C[WHEN]            --color[=WHEN]             Use color (auto, always, never)
  -i CODE1,CODE2..    --include=CODE1,CODE2..    Consider only given types of warnings
  -e CODE1,CODE2..    --exclude=CODE1,CODE2..    Exclude types of warnings
  -f FORMAT           --format=FORMAT            Output format (checkstyle, diff, gcc, json, json1, quiet, tty)
                      --list-optional            List checks disabled by default
                      --norc                     Don't look for .shellcheckrc files
  -o check1,check2..  --enable=check1,check2..   List of optional checks to enable (or 'all')
  -P SOURCEPATHS      --source-path=SOURCEPATHS  Specify path when looking for sourced files ("SCRIPTDIR" for script's dir)
  -s SHELLNAME        --shell=SHELLNAME          Specify dialect (sh, bash, dash, ksh)
  -S SEVERITY         --severity=SEVERITY        Minimum severity of errors to consider (error, warning, info, style)
  -V                  --version                  Print version information
  -W NUM              --wiki-link-count=NUM      The number of wiki links to show, when applicable
  -x                  --external-sources         Allow 'source' outside of FILES
                      --help                     Show this usage summary and exit

今回は、このまま使うことにします。

ShellCheckを使う

ShellCheckはシェルスクリプトの静的解析ツールなので確認対象のシェスクリプトが必要になりますが、これはShellCheckのWebサイトで
ランダムに提示されるスクリプトをそのまま使うことにしました。

sample.sh

#!/bin/bash
## Example: ShellCheck can detect many different kinds of quoting issues

if ! grep -q backup=true.* "~/.myconfig"
then
          echo 'Backup not enabled in $HOME/.myconfig, exiting'
            exit 1
fi

if [[ $1 =~ "-v(erbose)?" ]]
then
          verbose='-printf "Copying %f\n"'
fi

find backups/ \
          -iname *.tar.gz \
            $verbose \
              -exec scp {}  “myhost:backups” +

確認。

$ shellcheck sample.sh

In sample.sh line 4:
if ! grep -q backup=true.* "~/.myconfig"
             ^-----------^ SC2062: Quote the grep pattern so the shell won't interpret it.
                            ^---------^ SC2088: Tilde does not expand in quotes. Use $HOME.


In sample.sh line 6:
          echo 'Backup not enabled in $HOME/.myconfig, exiting'
               ^-- SC2016: Expressions don't expand in single quotes, use double quotes for that.


In sample.sh line 10:
if [[ $1 =~ "-v(erbose)?" ]]
            ^-----------^ SC2076: Don't quote right-hand side of =~, it'll match literally rather than as a regex.


In sample.sh line 12:
          verbose='-printf "Copying %f\n"'
                  ^----------------------^ SC2089: Quotes/backslashes will be treated literally. Use an array.


In sample.sh line 16:
          -iname *.tar.gz \
                 ^------^ SC2061: Quote the parameter to -iname so the shell won't interpret it.
                 ^-- SC2035: Use ./*glob* or -- *glob* so names with dashes won't become options.


In sample.sh line 17:
            $verbose \
            ^------^ SC2090: Quotes/backslashes in this variable will not be respected.
            ^------^ SC2086: Double quote to prevent globbing and word splitting.

Did you mean:
            "$verbose" \


In sample.sh line 18:
              -exec scp {}  “myhost:backups” +
                            ^-- SC1110: This is a unicode quote. Delete and retype it (or quote to make literal).
                                           ^-- SC1110: This is a unicode quote. Delete and retype it (or quote to make literal).

For more information:
  https://www.shellcheck.net/wiki/SC2076 -- Don't quote right-hand side of =~...
  https://www.shellcheck.net/wiki/SC1110 -- This is a unicode quote. Delete a...
  https://www.shellcheck.net/wiki/SC2061 -- Quote the parameter to -iname so ...

オンラインでの実行結果と同様の内容が検出されました。

設定方法は?ということですが、コメントでいろいろ書くようです。ホームディレクトリに.shellcheckrcというファイルを作成する方法も
あるようです。

Directive · koalaman/shellcheck Wiki · GitHub

特定のルールを無視する場合は、コメントで書くか、オプションで指定するか、.shellcheckrcに書くかといった感じですね。

Ignore · koalaman/shellcheck Wiki · GitHub

オプションで指定してみましょう。-eで指定します。

$ shellcheck -e SC2016 sample.sh

複数指定する場合は、,区切りで良いみたいです。-eオプションを繰り返しても動作しましたが。

$ shellcheck -e SC2016,SC1110 sample.sh
$ shellcheck -e SC2016 -e SC1110 sample.sh

Flycheckに組み込む

ShellCheckは、EmacsのFlycheckに組み込むことができるようです。

Flycheck — Syntax checking for GNU Emacs — Flycheck 33-cvs documentation

といっても、shellcheckコマンドにパスが通っていて、Flycheckがインストールされていればすぐに使えるようになりますが。

こんな感じですね。