ShellCheckの使い方

## 1. ShellCheckとは

- [github](https://github.com/koalaman/shellcheck/tree/master)
- [wiki](https://github.com/koalaman/shellcheck/wiki)
- [体験できるページ](https://www.shellcheck.net/)

シェルスクリプトのコードをチェックしてくれる**静的解析ツール**です。

文法的なお作法やエラーはもちろん、「この書き方は、特定の状況で意図しない動きをする可能性があるよ」といった落とし穴も指摘してくれます。

## 2. インストール方法

ShellCheckは様々な環境で簡単にインストールできます。

### macOS (Homebrew)

```bash
brew install shellcheck
```

### Ubuntu/Debian

```bash
sudo apt-get update && sudo apt-get install shellcheck
```

#### Windows (Scoop or Chocolatey)

**Scoopの場合:**

```bash
scoop install shellcheck
```

**Chocolateyの場合:**

```bash
choco install shellcheck
```

## 3. 基本的な使い方

ターミナルで `shellcheck` の後にファイル名を指定するだけです。

少し問題のあるスクリプト `test.sh` を用意してみます。

```bash:test.sh
#!/bin/bash

name="World"
echo Hello $name

files=*
echo $files

if [ $# -eq 1 ]; then
  echo "引数は1個です"
fi
```

このファイルをShellCheckでチェックしてみます。

```bash
shellcheck test.sh
```

すると、次のように問題点を教えてくれます。

```
In test.sh line 6:
files=*
      ^-- SC2125 (warning): Brace expansions and globs are literal in assignments. Quote it or use an array.


In test.sh line 7:
echo $files
     ^----^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
echo "$files"

For more information:
  https://www.shellcheck.net/wiki/SC2125 -- Brace expansions and globs are li...
  https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
```

`SC2086` は表示されている通り、「変数をダブルクォートで囲まないと、意図しない挙動（globbing and word splitting）を引き起こす可能性があるよ」という警告です。

`For more information` にある URL に行けば、より詳しい解説を読むこともできます。

### 3.1. コマンドラインオプション

多くのオプションがあります。ターミナルで以下のコマンドを実行するか、[公式](https://github.com/koalaman/shellcheck/blob/master/shellcheck.1.md)を参照してください。

* `man shellcheck`
* `shellcheck --help`

### 3.2. もっと便利に！エディタとの連携 (vscode)

毎回コマンドを打つのは面倒なので、エディタの拡張機能を使うとよいです。

vscodeであれば拡張機能があります。

1. vscodeの拡張機能を `shellcheck` で検索します。
2. `ShellCheck` (Timon Wong作) をインストールします。

![スクリーンショット 2025-06-07 095708.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193401/01a8daf2-eb08-4bb9-942d-b52a06fb2df1.png)

インストール後、`.sh` を開くと、問題のある箇所に自動で波線が表示され、マウスオーバーするとShellCheckからの指摘内容がポップアップで表示されるようになります。

### 3.3. 特定の警告を無視したいとき

コード内にコメントを書くことで、特定の警告を無効化できます。

```bash
# shellcheck disable=SC2086
echo $variable # この行のSC2086だけを無視する
```

### 3.4. 特定の警告をプロジェクト全体で無視したい場合

個別の行やファイルではなく、プロジェクト全体に適用したい場合、プロジェクトのルートディレクトリに設定ファイル `.shellcheckrc` を作成します。

```:.shellcheckrc
disable=SC2086
```

複数の警告を無効化したい場合はカンマで区切ります。

```:.shellcheckrc
disable=SC2125,SC2086
```

もしくは複数行に分けます。

```:.shellcheckrc
disable=SC2125
disable=SC2086
```

### 3.5. `.shellcheckrc` のその他の使い方

`.shellcheckrc`によって様々なルールを適用できます。詳細は [公式wiki](https://github.com/koalaman/shellcheck/wiki/Directive#source-path) を参照してください。

以下は、よく使われるディレクティブです。

| ディレクティブ | 説明 |
| :--- | :--- |
| `disable` | 指定した警告コード（例: `SC2086`）を無効にします。`SC1000-SC1999`のように範囲指定も可能です。 |
| `enable` | 標準では無効になっている追加のチェックを有効にします。どんなチェックがあるかは `shellcheck --list-optional` で確認できます。 |
| `external-sources` | スクリプト内で `source` や `.` コマンドで読み込まれている外部ファイルを、ShellCheckのチェック対象に含めるかどうかを設定します (`true`で有効)。セキュリティのため、デフォルトは`false`（無効）です。 |
| `source` | `source`コマンドで読み込むファイルパスが動的に変わる場合など、ShellCheckがファイルを見つけられないときに、そのファイルの場所を明示的に教えます。例: `# shellcheck source=path/to/file.sh` |
| `source-path` | `source`コマンドで読み込むファイルを探すディレクトリを指定します。`SCRIPTDIR`という特別な値を使うと、チェック対象のスクリプトと同じディレクトリを指定できて便利です。 |
| `shell` | スクリプトにシェバンがない場合に、どのシェル（`sh`, `bash`, `ksh`など）として解釈すべきかを指定します。例: `# shellcheck shell=bash` |

### 3.6. `.shellcheckrc` ファイルの置き場所

ShellCheckは、スクリプトをチェックする際に `.shellcheckrc` を探します。探す順番は以下の通りです。

1.  チェック対象のスクリプトがあるディレクトリ
2.  親ディレクトリを順に遡っていく
3.  ユーザーのホームディレクトリ (`~/.shellcheckrc`)
4.  XDG設定ディレクトリ (`~/.config/shellcheckrc`など)

最初に見つかったファイルだけが読み込まれ、それ以降は探しません。

## 4. ShellCheckの運用案

個人でShellCheckを使うだけでも便利ですが、チームで使うときの「仕組みづくり」について記載します。

### 4.1. コミット前の自動チェック (pre-commit)

`pre-commit`のインストールは済んでいるものとします。（例：pip install pre-commit）

1.  プロジェクトのルートに `.pre-commit-config.yaml` という設定ファイルを作成します。

    ```yaml:.pre-commit-config.yaml
    repos:
      - repo: https://github.com/shellcheck-py/shellcheck-py
        rev: v0.10.0 # 2025年6月時点の最新版。適宜更新してください。
        hooks:
          - id: shellcheck
    ```

2.  フックをインストールします。

    ```bash
    pre-commit install
    ```

これで、`git commit` を実行するたびに、ステージングされた `.sh` ファイルが自動的にShellCheckでチェックされ、問題があればコミットが中止されます。

### 4.2. Makefileによるローカルチェックの共通化

プロジェクトのルートに `Makefile` を作成し、以下のように記述します。

```makefile
# プロジェクト内の.shファイルをすべて検索 (node_modulesなどは除外)
SHELL_SCRIPTS := $(shell find . -type f -name "*.sh" -not -path "./node_modules/*")

.PHONY: lint shellcheck
# `make lint` で各種リンターを実行できるようにしておく
lint: shellcheck

# `make shellcheck` でShellCheckを実行
shellcheck:
	@echo "Running ShellCheck on all shell scripts..."
	@shellcheck $(SHELL_SCRIPTS)
```

これにより、 `make shellcheck` (または `make lint`) と打つだけでチェックを実行できます。


### 4.3. CI/CDへの統合

#### GitHub Actionsでの実装例

プロジェクトの `.github/workflows/` ディレクトリに、以下のようなYAMLファイルを作成します。

```yaml:.github/workflows/shellcheck.yml
name: ShellCheck

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  shellcheck:
    name: Run ShellCheck
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Run ShellCheck
        uses: ludeeus/action-shellcheck@v3 # または @master
        with:
          scandir: './' # リポジトリ全体をスキャン
```

この設定により、`main` ブランチへのpushやpull_request時に、リポジトリ内のすべてのシェルスクリプト (`.sh` および `#!/bin/sh` などで始まるファイル) が自動的にチェックされます。問題があればワークフローが失敗し、マージ前に修正を促すことができます。

#### reviewdogとの連携

[reviewdog](https://github.com/reviewdog/reviewdog) のようなツールと組み合わせると、ShellCheckの指摘をプルリクエストの該当行に直接コメントとして表示させることができ、レビュー体験が向上します。

```yaml:.github/workflows/reviewdog.yml
name: reviewdog

on:
  pull_request:

jobs:
  shellcheck:
    name: runner / shellcheck
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: reviewdog/action-shellcheck@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          reporter: github-pr-review # プルリクエストのレビューコメントとして報告
          level: warning # warningレベル以上の指摘を報告
```

## 5. さらに高度な使い方

`shellcheck` コマンドには、より柔軟な利用を可能にするためのオプションが用意されています。

### 出力フォーマットの変更 (`--format`)

`--format` (`-f`) オプションを使うと、出力形式を変更できます。CIツールや他の静的解析ツールと連携させる際に便利です。

* `json`: JSON形式で出力します。プログラムでパースしたいときに便利。
* `checkstyle`: Checkstyle形式のXMLで出力します。JenkinsなどのCIツールで広くサポートされています。
* `gcc`: GCCコンパイラのエラーメッセージ形式で出力します。多くのエディタがこの形式を解釈できます。

```bash
# JSON形式で出力
shellcheck --format=json test.sh
```