shellcheckでシェルスクリプトを静的解析する方法|インストールからCI組み込み・頻出警告の直し方まで

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)シェルスクリプト > shellcheckでシェルスクリプトを静的解析する方法|インストールからCI組み込み・頻出警告の直し方まで
「シェルスクリプトをテスト環境で動かしたのに、本番でいきなりエラーが出た」「ファイル名に空白が入っていてコマンドが期待どおり動かない」——こうしたトラブルの多くは、実行する前に shellcheck で発見できた問題だ。

bash や sh のスクリプトには型チェックもコンパイルもない。変数展開のクォート漏れ・バッククォートのネスト・非推奨構文といったバグは、実際に走らせてみるまで気づきにくい。

この記事では、shellcheck 静的解析の実践的な使い方を解説する。インストール方法(apt・dnf・brew・バイナリ)から、SC2086・SC2006・SC2046 など頻出警告の読み方と修正法、Vim・VS Code でのエディタ統合、そして GitHub Actions / GitLab CI への組み込みまでを実際の出力例と合わせて説明する。

動作確認環境: RHEL 9.4 / Rocky Linux 9.4 / Ubuntu 24.04 LTS / shellcheck 0.9.0

この記事のポイント

・shellcheck は実行前に静的解析でバグを検出するコマンドラインツール
・SC2086(クォート不足)・SC2006(バッククォート)が最多の警告パターン
・apt/dnf/brew/バイナリでインストール可能。GitHub Actions なら公式 Action あり
・set -x は実行時デバッグ、shellcheck は実行前の静的検査——役割がまったく異なる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

shellcheck とは何か——静的解析ツールとしての位置づけ

shellcheck(シェルチェック)は、bash・sh・ksh・dash スクリプトを対象にした静的解析ツールだ。スクリプトをいっさい実行せずに、ソースコードを解析して「バグになりやすいパターン」「非推奨の構文」「移植性の問題」を警告する。

警告は「SC+4桁番号」形式のコード(例: SC2086)で返される。各コードには原因・リスク・修正例が対応しており、shellcheck の公式 Wiki(https://www.shellcheck.net/wiki/)で詳細を確認できる。

現場での価値は、「実行してみるまで気づかなかった」バグを事前に排除できる点にある。たとえば、ファイルパスを含む変数をクォートなしで使っている箇所は、ファイル名に空白が入るまでエラーにならない。しかし shellcheck は「このコードは空白が入ったときに壊れる」と事前に指摘してくれる。

set -x(実行時デバッグ)との棲み分け

shellcheck と set -x はよく混同されるが、役割がまったく異なる。

shellcheck:実行前の静的検査。スクリプトを動かさずにバグを発見する
set -x:実行時のデバッグ。スクリプトを実際に走らせながらコマンド展開の結果をトレースする

基本の流れは「shellcheck でチェック → 問題なければ実行 → 動かないときは set -x でトレース」だ。本番環境への適用前は、必ず shellcheck を通しておくことを強く勧める。

shellcheck のインストール方法

1. Ubuntu / Debian(apt)

Ubuntu 24.04 LTS および Debian 系では apt で直接インストールできる。

# パッケージリストを更新してインストール $ sudo apt update $ sudo apt install shellcheck -y # バージョン確認 $ shellcheck --version ShellCheck - shell script analysis tool version: 0.9.0 license: GNU General Public License, version 3

2. RHEL / Rocky Linux / AlmaLinux(dnf)

RHEL 9.x 系では EPEL リポジトリを有効化してからインストールする。

# EPEL を有効化(RHEL 9 / Rocky Linux 9 / AlmaLinux 9) $ sudo dnf install epel-release -y # shellcheck をインストール $ sudo dnf install shellcheck -y # バージョン確認 $ shellcheck --version ShellCheck - shell script analysis tool version: 0.9.0

3. macOS(Homebrew)

自分の PC(macOS)で開発中のスクリプトをリアルタイムにチェックしたい場合は Homebrew でインストールできる。

$ brew install shellcheck # バージョン確認 $ shellcheck --version ShellCheck - shell script analysis tool version: 0.9.0

4. バイナリを直接インストール(Linux 汎用)

パッケージマネージャーが使えない環境や最新版を使いたい場合は、GitHub リリースページからバイナリを取得できる。

# 最新バイナリをダウンロード(x86_64 の場合) $ wget -O shellcheck.tar.xz \ https://github.com/koalaman/shellcheck/releases/download/v0.9.0/shellcheck-v0.9.0.linux.x86_64.tar.xz # 展開してパスを通す $ tar -xf shellcheck.tar.xz $ sudo cp shellcheck-v0.9.0/shellcheck /usr/local/bin/ $ shellcheck --version ShellCheck - shell script analysis tool version: 0.9.0

shellcheck の基本的な使い方

1. 単一ファイルをチェックする

あえてバグを含んだサンプルスクリプトを用意して試してみよう。

#!/bin/bash # sample.sh — わざとバグを含んだサンプル name="World" echo "Hello $name!" # バッククォートで囲んだコマンド置換(SC2006 の例) files=`ls /tmp` # クォートなしの変数展開(SC2086 の例) echo $files

このファイルに shellcheck を実行した結果が以下だ。

$ shellcheck sample.sh In sample.sh line 9: files=`ls /tmp` ^--------^ SC2006 (style): Use $(...) instead of legacy `...`. In sample.sh line 12: echo $files ^----^ SC2086 (info): Double quote to prevent globbing and word splitting. Did you mean: echo "$files"

警告は「ファイル名・行番号・問題箇所・警告コード・説明・修正例」の順に表示される。終了コードは警告があると 1 以上になる。

2. 複数ファイルをまとめてチェックする

# ワイルドカードで一括チェック $ shellcheck scripts/*.sh # find と組み合わせてサブディレクトリも含めて再帰チェック $ find . -name "*.sh" -exec shellcheck {} +

3. 終了コードと CI での活用

shellcheck は問題がない場合は終了コード 0、警告・エラーがある場合は 1 以上を返す。この性質を活用して CI のゲートとして使える。

# 警告ありのスクリプトをチェック $ shellcheck sample.sh $ echo $? 1 # 問題なしのスクリプトをチェック $ shellcheck clean.sh $ echo $? 0

CI パイプラインに組み込めば「shellcheck を通らないスクリプトはマージできない」仕組みを作れる。

頻出警告パターンと修正方法

shellcheck の警告の中でも特に頻繁に遭遇する 3 つのコードを解説する。これだけ押さえておけばスクリプト品質が大幅に向上する。

SC2086——変数展開のクォート不足(最頻出)

症状: 変数をダブルクォートなしで使用している。

なぜ問題か: $var はそのまま展開されるが、値に空白が含まれると複数の引数として分割される(ワードスプリット)。また *? がグロブ展開される恐れもある。

#!/bin/bash # NG — クォートなし filepath="/tmp/my file.txt" cat $filepath # 「/tmp/my」と「file.txt」の 2 引数に分割される! # OK — ダブルクォートで囲む cat "$filepath" # ファイルパス全体が 1 引数として渡る

修正方法: 変数展開は原則としてダブルクォートで囲む。"$variable" の形が基本だ。

SC2006——バッククォートの使用

症状: コマンド置換にバッククォート(`command`)を使用している。

なぜ問題か: バッククォートはネストが難しく、エスケープも複雑になる。現代の bash では $(command) 形式が推奨されている。

#!/bin/bash # NG — バッククォート形式 result=`date +%Y%m%d` # OK — $() 形式 result=$(date +%Y%m%d) # ネストする場合も $() なら可読性が高い nested=$(echo $(date +%Y))

修正方法: バッククォートをすべて $() に書き換える。動作は同じで可読性・保守性が向上する。

SC2046——クォートなしのコマンド置換

症状: コマンド置換の結果をダブルクォートで囲んでいない。

なぜ問題か: SC2086 と同様に、コマンドが返す値に空白を含む場合、ワードスプリットが発生する。ファイルパスを取得するコマンド置換では特に深刻なバグになりやすい。

#!/bin/bash # NG — クォートなし(スペースを含むパスで壊れる) cd $(dirname $0) # OK — コマンド置換全体をダブルクォートで囲む cd "$(dirname "$0")"

修正方法: コマンド置換 $() 全体をダブルクォートで囲む。"$(command)" の形が基本だ。

シェルスクリプトの品質をもっと高めたい方へ

現役エンジニアが解説するシェルスクリプト実践講座・無料メルマガ配信中

無料メルマガを読む >>

エディタとの統合

shellcheck は CLI だけでなく、主要なエディタと統合して「書きながらリアルタイムに警告を確認」できる環境を整えられる。

Vim / Neovim(ALE プラグイン)

ALE(Asynchronous Lint Engine)プラグインを使うと、.sh ファイルを開いた瞬間に shellcheck が自動で走る。

" .vimrc または init.vim に追加 let g:ale_linters = {'sh': ['shellcheck']} let g:ale_sh_shellcheck_options = '--severity=warning' " 保存時だけチェックする場合(リアルタイムチェックをオフ) let g:ale_lint_on_text_changed = 'never' let g:ale_lint_on_insert_leave = 0

ALE をインストールして上記を設定すると、警告箇所に下線が入り、ステータスバーにエラー数が表示される。

VS Code(shellcheck 拡張)

VS Code では shellcheck 拡張(timonwong.shellcheck)をインストールするだけで利用できる。

# VS Code 拡張をコマンドラインからインストール $ code --install-extension timonwong.shellcheck

インストール後は .sh ファイルを開くと自動的に shellcheck が実行される。警告箇所には波線が表示され、ホバーで詳細と修正例を確認できる。事前にシステムへ shellcheck バイナリをインストールしておく必要がある。

GitHub Actions / GitLab CI への CI 組み込み

GitHub Actions

shellcheck を GitHub Actions で自動実行する最も手軽な方法は、ludeeus/action-shellcheck 公式 Action を使うことだ。

# .github/workflows/shellcheck.yml name: ShellCheck on: push: branches: [main, develop] pull_request: jobs: shellcheck: name: ShellCheck runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run ShellCheck uses: ludeeus/action-shellcheck@master with: severity: warning # warning 以上を検出対象に scandir: './scripts' # チェック対象ディレクトリを指定

severity には errorwarninginfostyle を指定できる。CI のゲートとしては warning 以上を対象にするのが一般的だ。PR が出るたびに自動でスクリプト品質を検証できる。

GitLab CI

GitLab CI では shellcheck の公式 Docker イメージを使ってシェルコマンドとして直接実行する。

# .gitlab-ci.yml shellcheck: image: koalaman/shellcheck-alpine:stable stage: test script: - find . -name "*.sh" -exec shellcheck -S warning {} + only: - merge_requests - main

koalaman/shellcheck-alpine は shellcheck の公式 Docker イメージ(Alpine ベース)で、追加インストール不要でそのまま利用できる。-S warning オプションは warning 以上のみを終了コード 1 扱いにするオプションだ。

よくあるエラーと対処法

「SC2148: Tips depend on target shell」が出た場合

shebang 行(#!/bin/bash など)がないスクリプトをチェックすると SC2148 が出ることがある。

# SC2148 が出るケース — shebang なし name="World" echo "$name" # 解決策1: shebang を先頭に追加する #!/bin/bash name="World" echo "$name" # 解決策2: -s オプションで対象シェルを明示する $ shellcheck -s bash myscript.sh

特定の警告を無効化したい場合(disable コメント)

どうしても警告を抑制しなければならない箇所には、インラインコメントで無効化できる。注意: disable コメントを多用するとスクリプト全体の品質が下がるため、最小限にとどめること。原則として「警告の原因を修正する」のが鉄則だ。

# 特定行だけ SC2086 を無効化(行の直前に記述) # shellcheck disable=SC2086 echo $unquoted_var # 複数コードをまとめて無効化 # shellcheck disable=SC2086,SC2006 echo $var1 files=`ls /tmp` # ファイル全体で無効化(ファイル先頭に記述) # shellcheck disable=SC2086

本記事のまとめ

shellcheck を使ったシェルスクリプト静的解析の手順と主なポイントをまとめる。
やりたいこと コマンド・設定
インストール(Ubuntu/Debian) sudo apt install shellcheck
インストール(RHEL/Rocky Linux) sudo dnf install shellcheck
インストール(macOS) brew install shellcheck
単一ファイルをチェック shellcheck script.sh
ディレクトリ内の全 .sh をチェック find . -name "*.sh" -exec shellcheck {} +
対象シェルを明示して実行 shellcheck -s bash script.sh
warning 以上だけ検出する shellcheck -S warning script.sh
特定警告を 1 行だけ無効化 # shellcheck disable=SC2086
・SC2086(クォート不足)は最頻出の警告。変数展開は常に "$var" で囲む習慣をつける
・SC2006(バッククォート)は $() 形式に書き換えるだけで解消する
・CI に組み込むと「警告ありのままマージ」を防止できる品質ゲートを作れる
・shellcheck は実行前の静的検査、set -x は実行時のトレース——2 つを組み合わせて使うのが基本
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアが基礎から教えます。
Linux無料マニュアルを受け取る >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。