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 は実行前の静的検査——役割がまったく異なる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
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 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"
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
頻出警告パターンと修正方法
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
VS Code(shellcheck 拡張)
VS Code では shellcheck 拡張(timonwong.shellcheck)をインストールするだけで利用できる。# VS Code 拡張をコマンドラインからインストール $ code --install-extension timonwong.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 には error・warning・info・style を指定できる。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 |
"$var" で囲む習慣をつける・SC2006(バッククォート)は
$() 形式に書き換えるだけで解消する・CI に組み込むと「警告ありのままマージ」を防止できる品質ゲートを作れる
・shellcheck は実行前の静的検査、set -x は実行時のトレース——2 つを組み合わせて使うのが基本
Linux無料マニュアルを受け取る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 次のページへ:bashのパラメータ展開で文字列処理を完結させる方法|${var%}・${var//}でsed・awkの外部呼び出しを減らす設計
- 前のページへ:bashで関数を定義して再利用する方法|シェルスクリプトのライブラリ化と実践例
- この記事の属するカテゴリ:シェルスクリプトへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます