「ShellCheck」を使って、メンテナンス性の高いシェルスクリプトを実装する
ShellCheckとは
ShellCheckは、シェルスクリプトの静的解析ツールで、マズい書き方をしてると怒ってくれるLinterだ。
たとえば、example.sh
という下記のシェルスクリプトがあるとしよう。
echo $0
これをShellCheckでチェックすると、こんな警告を出してくれる。
In example.sh line 1: echo $0 ^-- SC2148: Tips depend on target shell and yours is unknown. Add a shebang. ^-- SC2086: Double quote to prevent globbing and word splitting.
この例では、「shebangを書け」「変数使うときはダブルクォート使え」的な指摘をしてくれる。
インストール
公式でDockerイメージが提供されているので、それを使うのが簡単だ。筆者はDocker版を使っている。
$ docker pull koalaman/shellcheck:stable
macOSであれば、Homebrewでインストールしてもよい。
$ brew install shellcheck
使い方
ここではDocker版をベースに紹介する。
ベーシックな使い方
単純にチェックしたいファイルを指定して実行する。
$ docker run --rm -t -v "$PWD:/mnt" koalaman/shellcheck example.sh
余談だが、docker runの-t
オプションがないと、カラー出力されないので、Docker版使う場合は認識しておこう。
特定のルールを無視する
記事の冒頭で紹介した例で、SC2086
だけ除外したいという場合は、--exclude
オプションを指定しよう。
$ docker run --rm -v "$PWD:/mnt" koalaman/shellcheck --exclude=SC2086 example.sh In example.sh line 1: echo $0 ^-- SC2148: Tips depend on target shell and yours is unknown. Add a shebang.
出力フォーマットの指定
--format
オプションで指定できる。選べるフォーマットは「tty、json、checkstyle、gcc」だ。
tty
デフォルトはttyで、何も指定しない場合と同様の結果になる。
$ docker run --rm -t -v "$PWD:/mnt" koalaman/shellcheck --format=tty example.sh In example.sh line 1: echo $0 ^-- SC2148: Tips depend on target shell and yours is unknown. Add a shebang. ^-- SC2086: Double quote to prevent globbing and word splitting.
json
他のCLIツールと組み合わせるなら、json形式が役立つかもしれない。
$ docker run --rm -v "$PWD:/mnt" koalaman/shellcheck --format=json example.sh | jq . [ { "file": "example.sh", "line": 1, "endLine": 2, "column": 1, "endColumn": 1, "level": "error", "code": 2148, "message": "Tips depend on target shell and yours is unknown. Add a shebang." }, { "file": "example.sh", "line": 1, "endLine": 1, "column": 6, "endColumn": 8, "level": "info", "code": 2086, "message": "Double quote to prevent globbing and word splitting." } ]
checkstyle
CIでCheckStyleを使っている場合は、checkstyle形式で出力すると便利だろう。
$ docker run --rm -v "$PWD:/mnt" koalaman/shellcheck --format=checkstyle example.sh <?xml version='1.0' encoding='UTF-8'?> <checkstyle version='4.3'> <file name='example.sh' > <error line='1' column='1' severity='error' message='Tips depend on target shell and yours is unknown. Add a shebang.' source='ShellCheck.SC2148' /> <error line='1' column='6' severity='info' message='Double quote to prevent globbing and word splitting.' source='ShellCheck.SC2086' /> </file> </checkstyle>
gcc
gcc系のエラーメッセージのフォーマットっぽい。(よく知らない
docker run --rm -v "$PWD:/mnt" koalaman/shellcheck --format=gcc example.sh example.sh:1:1: error: Tips depend on target shell and yours is unknown. Add a shebang. [SC2148] example.sh:1:6: note: Double quote to prevent globbing and word splitting. [SC2086]
severityの指定
--severity
オプションでseverityを指定できる。「error、warning、info、style」から選択でき、何も指定しない場合、style
が指定されたものとして動くらしい。
たとえば、最初の例をerrorレベルにした場合、警告の数が減る。
$ docker run --rm -v "$PWD:/mnt" koalaman/shellcheck --severity=error example.sh In example.sh line 1: echo $0 ^-- SC2148: Tips depend on target shell and yours is unknown. Add a shebang.
infoレベルにすると、警告は元通り表示される。
$ docker run --rm -v "$PWD:/mnt" koalaman/shellcheck --severity=info example.sh In example.sh line 1: echo $0 ^-- SC2148: Tips depend on target shell and yours is unknown. Add a shebang. ^-- SC2086: Double quote to prevent globbing and word splitting.
ヘルプ
なぜか--help
オプションが実装されてないが、引数なしで実行するとちゃんと表示してくれる。
$ docker run --rm koalaman/shellcheck No files specified. Usage: shellcheck [OPTIONS...] FILES... -a --check-sourced Include warnings from sourced files -C[WHEN] --color[=WHEN] Use color (auto, always, never) -e CODE1,CODE2.. --exclude=CODE1,CODE2.. Exclude types of warnings -f FORMAT --format=FORMAT Output format (checkstyle, gcc, json, tty) -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 -x --external-sources Allow 'source' outside of FILES
バージョン
オーソドックスに--version
オプションを使えばOK。
$ docker run --rm koalaman/shellcheck --version ShellCheck - shell script analysis tool version: 0.5.0 license: GNU General Public License, version 3 website: https://www.shellcheck.net
シェルスクリプト内に除外設定を定義
あんまり乱用すべきではないが、このワーニングだけは許してくれ!ってときには、ソースコードに直接除外設定を書くこともできる。
# shellcheck disable=SC2148 echo $0
ルールの詳細
怒られたけど何をすればいいのか分からないという場合は、各ルールの詳細を参照しよう。
GitHub
詳細はGitHubのWikiからたどることができる。少しわかりづらいが、右側のPages
をクリックすると、Wikiの記事一覧が出てくるので、そこから目当ての記事を探せばよい。
例えば、SC2086について知りたい場合は、下記URLにアクセスする。
ターミナル
ブラウザを開くのがメンドウであれば、~/.zshrc
とか~/.bashrc
とかに雑にfunction定義しておくと、ターミナルで確認できて便利である。
function schelp() { curl -s https://raw.githubusercontent.com/wiki/koalaman/shellcheck/"$1".md }
おわりに
シェルスクリプトは適当に書き散らすことも多いが、ShellCheckを使えばメンテナンス性の高いコードを実装する一助になるので、ぜひ一度試しみてはいかがだろうか。