Claude Codeでコマンド実行の権限設計を意識し始めた人向け
料理ブログに記事を追加した後にHugoでビルドが通るか確認してgitにコミットしたい時など、ターミナルでコマンドを順番に叩く作業をClaude Codeの中で完結させたい場面で使う。専用ツール(Read/Write/Edit/Glob/Grep)で済む作業はそちらを優先し、それ以外の手順実行に限って呼び出すのが基本。
噛み砕くと
私のキーボードと、Claudeのキーボードを並べて置いてあるイメージです。私が「このコマンド叩いて」と言うと、Claudeが代理で叩く。打ち込んだ結果は両方のキーボードから同じ画面に流れます。
Read(ファイルを読む)、Write(ファイルを書く)、Edit(ファイルの一部を直す)みたいな専用ツールでカバーできない作業がたくさんあります。テストを走らせる、Hugoでサイトをビルドする、git でコミットする、依存パッケージを入れる。こういう「手順を進める系」は全部Bashの守備範囲です。
ただ、力が強い。
rm -rf 1発でフォルダごと消し飛ばせるツールでもあります。だから初回は1コマンドずつ「これ叩いていい?」と確認を取る作りになっています。
Bash を呼ぶと画面に何が出るのか
料理ブログのフォルダで「いまリポジトリの状態どう?」とClaudeに聞くと、こういう動きをします。
● Bash(git status)
⎿ On branch main
Changes not committed to commit:
modified: content/recipes/sukiyaki.md
new file: content/recipes/oden.md
「Bash(git status)」が呼んだツール名と実行したコマンド、その下の ⎿ の中が画面に返ってきた中身。普段ターミナルで git status を叩いた時に出るのと同じものが、Claudeの応答ブロックの中に流れます。
初回や許可されていないコマンドの時は、こんな確認が挟まります。
Claude wants to run:
git status
[1] Yes
[2] Yes, don't ask again for `git status`
[3] No, tell Claude what to do differently
1を押せばその場限りで実行、2を押すと git status はこの先聞かずに実行、3で却下できます。2を押した分は .claude/settings.local.json の許可リストに保存されて、次回以降は素通りで通ります。
料理ブログで「記事追加→ビルド確認→コミット」を Bash で連続実行する再現手順
すき焼き記事を Write で新規作成した直後、Hugoでサイトのビルドが通るか確認して、問題なければ git にコミットしたい。この一連の流れを再現してみます。
ステップ1: いまのフォルダの状態を確認する
料理ブログのフォルダでClaude Codeを起動して、こう頼みます。
> いまのリポジトリの状態を見せて
ClaudeがBashで git status を叩いて、変更があるファイルを返してきます。
● Bash(git status)
⎿ modified: content/recipes/sukiyaki.md
new file: content/recipes/oden.md
すき焼きとおでん、2本の記事を追加・修正した状態だと分かります。
ステップ2: Hugoでサイトのビルドが通るか確認する
記事を追加した後にビルドが壊れていないかは、コミット前に確認したい。「Hugo でビルド通るか試して」と頼みます。
● Bash(hugo --quiet)
⎿ Start building sites …
Pages | 18
Static files | 24
Total in 142 ms
142msでビルドが通ったので、新しい記事もテンプレートと食い違っていないと分かります。ここでエラーが出ていれば、次の commit には進まずに記事側を直します。
この順番が大事。
ビルドが壊れた状態でコミットを作ると、後で履歴を追った時に「どこから壊れたか」が分かりにくくなります。
ステップ3: 変更をステージに上げてコミットする
「変更をステージに乗せて、すき焼き追加のコミット作って」と頼みます。Claudeは git add と git commit を順番にBashで叩きます。
● Bash(git add content/recipes/sukiyaki.md content/recipes/oden.md)
⎿ (no output)
● Bash(git commit -m "add sukiyaki and oden recipe articles")
⎿ [main 3f2a1b9] add sukiyaki and oden recipe articles
2 files changed, 84 insertions(+)
2回のBash呼び出しで、ステージに乗せる→コミット作成、まで進みました。git push はあえてここでは走らせず、私が確認してから別途指示します。
ステップ4: 同じ流れを次回も自動化したいなら許可リストに登録
毎回 git status や hugo --quiet で「叩いていい?」を聞かれるのは面倒です。確認画面の[2] Yes, don't ask againを選ぶと、この先は素通りで通るようになります。あるいは .claude/settings.local.json の permissions.allow に直接書いておく形でも同じ効果になります。
{
"permissions": {
"allow": [
"Bash(git status)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(hugo --quiet)"
],
"deny": [
"Bash(git push *)"
]
}
}
git push だけは deny に入れて、本番反映は手動でやる、みたいな線引きが現実的です。
Read/Write/Edit で済むのに Bash で済ませる──新人がよくやる事故
これが結構ハマるところです。Bashは何でもできるので、ファイル操作までBashで済ませようとする人がいます。cat content/recipes/sukiyaki.md でファイルを読む、echo "..." > new.md でファイルを作る、sed -i 's/古い/新しい/' file.md で置換する、みたいな。
Claude Codeの公式ガイドはこれを明確に避けるよう指示しています。理由は3つあります。
- 専用ツールの方が安全。Read/Write/Editは編集前後の差分や行数を返してくれます。Bashの
sed -iは静かに上書きするので、何が変わったか後追いしづらい - 専用ツールの方が壊れにくい。
echo "..." > file.mdはファイル名のクォート漏れや特殊文字で簡単に壊れます。Writeはパスと中身を直接受け取るので、シェルの解釈ミスが入りません - ログが追いやすい。Read/Write/Editは「ファイルAを変えた」が応答にそのまま出ます。Bashの
sedは何ファイルに何が起きたか応答だけ見ても分からない
ここは結構効く。
使い分けの判断ライン:
- ファイルの中身を見る:
cat / head / tailではなく Read - ファイル全体を新規作成・全置換する:
echo >ではなく Write - ファイルの一部だけ書き換える:
sed -iではなく Edit - ファイル名やフォルダを探す:
findではなく Glob - ファイルの中身から検索する:
grepではなく Grep(専用ツール) - これら以外の手順実行: Bash(
git,hugo,npm, テストランナー等)
Claudeも内部で「ファイル系の専用ツールを優先、Bashは手順実行に限定」を推奨基準として動きます。明示的に「cat で見せて」と頼まない限り、Bashで cat や sed がいきなり選ばれることは少ないです。
ただ、依頼の言い回し次第でBashに流れる場合があります。「ファイルの末尾だけ見せて」と頼むとBashの tail に行きやすい。「Readで開いて、最後の20行だけ表示して」と限定したほうが事故が減ります。
料理ブログでの使いどころ
シナリオ1: テスト・ビルド・lintをまとめて回す
レシピ記事を10本書き溜めた後、Markdownの書式チェック・Hugoビルド・リンク切れチェックを1回で回したい。「npm run lint、hugo、npm run check-links を順に走らせて」と頼むと、Bashが3回呼ばれて結果が画面に並びます。失敗したら次のコマンドはスキップさせる、までClaudeに任せられます。
シナリオ2: バックグラウンドで開発サーバーを立ち上げて、その間に記事を書く
Hugoの開発サーバー(hugo server)はターミナルを1個占有するコマンドです。普通に叩くとClaudeも応答できなくなります。Bashのrun_in_background: trueで叩くと、サーバーは裏で動き続けて、Claudeは別の作業を続けられます。記事を書きながら、ブラウザで localhost:1313 を開いてプレビューを確認、みたいな並行作業ができます。
● Bash(hugo server, run_in_background: true)
⎿ Web Server is available at http://localhost:1313/
Press Ctrl+C to stop
裏で動いているサーバーの様子は BashOutput ツールで覗けて、止めたい時は KillShell で落とせます。
シナリオ3: 公開フォルダを丸ごとデプロイ用フォルダに同期する
Hugoでビルドした public/ の中身を、デプロイ用の別フォルダに rsync で同期したい。これは Read/Write/Edit ではどうにもならない手順系の作業です。Bashで rsync -av public/ ~/deploy/cooking-blog/ を1回叩くだけで終わります。
初心者が踏みやすい落とし穴
cdでプロジェクトの外に出ると作業ディレクトリがリセットされる。メインセッションではcdの移動が次のBashコマンドに引き継がれます。ただし、プロジェクトディレクトリ(または--add-dirや/add-dirで追加したフォルダ)の外に出ると、自動でプロジェクトディレクトリに戻されて、応答にShell cwd was reset to ...が追記されます。サブエージェントの場合はcd自体が次に持ち越されないので、絶対パスで指定するかcd ~/projects/cooking-blog && lsのように1コマンドに繋ぐexport FOO=barは次のコマンドに引き継がれない。Bashでexportした環境変数は、次のBash呼び出しでは消えています(公式がcdとは挙動が違うと明記している点)。永続化したい時はCLAUDE_ENV_FILEにシェルスクリプトを指定するか、SessionStartフックで毎回読ませるfind / -name "..."で/から走らせる。ルートから検索を走らせるとマウントしている全ドライブを舐めて、リソースを食い潰します。find . -name "..."またはfind ~/projects/cooking-blog -name "..."のように、特定パスから走らせる- デフォルト2分のタイムアウトを忘れる。長時間ビルドや大きいテストは、デフォルトの120,000ms(2分)で打ち切られます。最大10分(600,000ms)まで
timeoutを伸ばせるので、長時間処理は明示的に指定する - 許可リストの書き方が雑で意図せず通る。
Bash(devbox run *)を許可すると、devbox run rm -rf .も通ってしまいます。runner系のコマンドを許可する時はBash(devbox run npm test)のように、中身まで指定する - 複合コマンドの読み違い。
Bash(safe-cmd *)を許可しても、safe-cmd && other-cmdのother-cmd側は別判定になります。複合コマンドは&&,||,;,|単位で1個ずつ許可がチェックされる、と覚えておく watchやfind -deleteはパターン許可できない。これらは安全上、必ず毎回確認が入る仕様です。Bash(watch *)を許可リストに書いても素通りはしません
関連するコマンド・ツールへの動線
- Read(リード) - ファイルの中身をClaudeに見せるツール。
catやheadをBashで叩く代わりに使う - Write(ライト) - ファイルを新規作成・全置換するツール。
echo >をBashで叩く代わりに使う - /init(イニット) - プロジェクト用の覚え書き
CLAUDE.mdの雛形を半自動で作るスラッシュコマンド。料理ブログを始めた初日に1回叩く - /memory(メモリー) -
CLAUDE.mdを直接開いて手で編集するスラッシュコマンド。Bashの許可リストの調整にも使う - CLAUDE.md(クロードドットエムディー) - プロジェクト用の覚え書きファイル本体。「
npm testを使うプロジェクト」など、Bashが使うべき手順をここに書いておく - /agents(エージェンツ) - 専門エージェントの管理画面を開くスラッシュコマンド。エージェントごとにBash使用の可否を細かく分けられる
- /clear(クリア) - 会話履歴をリセットするスラッシュコマンド。Bashで長時間ビルドのログを大量に出した後に呼ぶことが多い
- /compact(コンパクト) - 会話履歴を要約して圧縮するスラッシュコマンド。Bashの大量ログを整理する場面で使う
- Skills(スキルズ) - 再利用できる作業手順をまとめておく仕組み。スキルの中で
!`コマンド`記法を使うとBashが呼び出される - Hooks(フックス) - ツール実行の前後に処理を差し込む仕組み。Bash実行の直前に「このコマンドは止める」を判定する PreToolUse フックがよく使われる
- MCP(エムシーピー) - Claude Codeに外部ツールを足す仕組み。Bashで叩く代わりに、専用のMCPツールを足して安全に作業させる選択肢になる
参考リンク
書き方
Claudeが内部でコマンド文字列を組み立ててBashツールに渡す。ユーザーが直接叩く形ではなく、自然文(「git status見せて」など)で頼んだ結果としてBashが呼ばれる。設定ファイル <code>.claude/settings.local.json</code> の <code>permissions.allow</code> に <code>Bash(git status)</code> や <code>Bash(npm run *)</code> のように許可ルールを書いておくと、毎回の確認なしで実行される。
やってみるとこうなる
入力
> いまのリポジトリの状態を見せて
(Claudeが内部で git status をBashに渡す)
出力例
● Bash(git status)
⎿ On branch main
Changes not committed to commit:
modified: content/recipes/sukiyaki.md
new file: content/recipes/oden.md
このページに出てきた言葉
- シェル
- ターミナルの中で動いている、コマンドを受け付けるプログラム。Macや多くのLinuxは bash や zsh、Windowsは PowerShell
- ターミナル
- 黒い画面で文字のコマンドを打ち込む画面。Windowsだと「コマンドプロンプト」「PowerShell」、Macだと「ターミナル」アプリ
- 標準出力(stdout)
- コマンドが「正常な結果」を流す出口。<code>git status</code> の表示や <code>echo</code> の文字はここに出る
- 標準エラー(stderr)
- コマンドが「エラーや警告」を流す出口。標準出力と分かれている
- 終了コード(exit code)
- コマンドが終わる時に返す数字。0なら成功、それ以外は失敗
- バックグラウンド実行
- コマンドを「裏で動かしたまま、別の作業を続ける」モード。<code>run_in_background: true</code> で指定する
- rm -rf
- 指定したフォルダを中身ごと丸ごと消すコマンド。確認なしで一発で消えるので、ホームディレクトリ直下では取り返しがつかない
- リポジトリ
- プロジェクトのファイル一式と変更履歴をまとめて保存する箱。GitHubで「リポジトリ」と呼んでいるあれ
- ビルド
- テンプレートと記事から、公開用のHTMLファイル群を生成する処理。ビルドが通る = サイトとして公開できる状態
- コミット
- 変更を「ここまで保存」と区切る操作。後から「この時点に戻す」が可能になる
- プッシュ
- ローカル(手元のパソコン)のコミットを、GitHubなどのリモートに送る操作