Bashツール
Claudeがシェルコマンドをリクエストし、アプリケーションが永続的なbashセッションでそれを実行してツール結果として返せるようにします。
bashツールはクライアントツールです。Claude自身がコマンドを実行するわけではありません。リクエストにこのツールを含めると、Claudeは実行すべきコマンドを指定した tool_use ブロックで応答します。アプリケーションは自身が所有するbashセッションでそのコマンドを実行し、出力を tool_result ブロックで返します。
アプリケーションはツール呼び出しをまたいで1つのbashプロセスを維持するため、コマンド間で状態が保持されます。作業ディレクトリ、環境変数、コマンドが作成したファイルは、次のコマンドでもそのまま残っています。
このツールの現在のバージョンは bash_20250124 です。モデルのサポート、ベータヘッダー、および以前のバージョンについては、ツールのバージョンを参照してください。Anthropicが提供するすべてのツールについては、ツールリファレンスを参照してください。
ユースケース
- 開発ワークフロー: ビルドコマンド、テスト、開発ツールを実行する
- システム自動化: スクリプトの実行、ファイルの管理、タスクの自動化
- データ処理: ファイルの処理、分析スクリプトの実行、データセットの管理
- 環境セットアップ: パッケージのインストール、環境の設定
クイックスタート
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
tools=[{"type": "bash_20250124", "name": "bash"}],
messages=[
{"role": "user", "content": "List all Python files in the current directory."}
],
)
print(response)Claudeは stop_reason: "tool_use" と、アプリケーションが実行すべきコマンドを含む tool_use ブロックで応答します。
{
"id": "msg_01XAbCDeFgHiJkLmNoPQrStU",
"model": "claude-opus-5-5",
"stop_reason": "tool_use",
"role": "assistant",
"content": [
{
"type": "text",
"text": "I'll list all Python files in the current directory for you."
},
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "bash",
"input": {
"command": "ls *.py"
}
}
]
}bashセッションで input.command を実行し、出力を tool_result として送り返します。ラウンドトリップについてはbashツールを実装するを参照してください。
仕組み
各ツール呼び出しは、Claudeとアプリケーションの間の1回のラウンドトリップです。
- Claudeが実行すべき
commandを含むtool_useブロックを返します。 - アプリケーションがそのコマンドを自身のbashセッションで実行します。
- アプリケーションがコマンドの出力(stdoutとstderrをまとめたもの)を
tool_resultブロックでClaudeに返します。 - Claudeは同じセッションで別のコマンドをリクエストするか、テキストで応答します。
Claudeは1つの応答で複数の tool_use ブロックを返すこともあります。それらを同じセッションで順番に実行し、すべての結果を1つの user メッセージで返してください。並列ツール使用を参照してください。
APIはステートレスです。シェルセッションに関する情報はリクエスト間で一切やり取りされないため、セッションをいつ開始し、どれだけ存続させ、いつ再起動するかはアプリケーションが決定します。リクエストとレスポンスの完全なサイクルについては、ツール呼び出しの処理を参照してください。
パラメータ
bashツールの定義には type と name の2つの必須フィールドがあり、name は bash でなければなりません。このツールはスキーマレスです。スキーマはClaudeのモデルに組み込まれており変更できないため、input_schema は指定しません。次の表は、Claudeがツールを呼び出す際に設定する入力フィールドの一覧です。
| パラメータ | 必須 | 説明 |
|---|---|---|
command | はい* | 実行するbashコマンド |
restart | いいえ | bashセッションを再起動するには true に設定 |
*restart を使用しない場合は必須
restart: true を処理するには、シェルプロセスを終了して新しいプロセスを開始し、再起動を確認する tool_result を返します。再起動されたセッションはクリーンな状態から始まります。作業ディレクトリ、環境変数、実行中のプロセスはすべて失われます。
コマンドを実行する:
{
"command": "ls -la *.py"
}セッションを再起動する:
{
"restart": true
}ツールのバージョン
bash_20250124 はこのツールの現在のバージョンであり、ベータヘッダーは不要です。Claude Sonnet 3.7(廃止済み)以降のすべてのモデルがこれを受け付けます。現在のすべてのClaudeモデルも含まれます。
オリジナルの bash_20241022 バージョンは、2024年10月のClaude Sonnet 3.5モデル(廃止済み)でのみ動作します。これを使用するリクエストには anthropic-beta: computer-use-2024-10-22 ヘッダーが必要で、SDKではベータ名前空間でのみ公開されています。新しい統合では bash_20250124 を使用してください。
例: マルチステップの自動化
Claudeはツール呼び出しをまたいでコマンドを連鎖させ、マルチステップのタスクを完了できます。
User request:
"Install the requests library and create a simple Python script that
fetches a joke from an API, then run it."
Claude's tool uses:
1. Install package
{"command": "pip install requests"}
2. Create script
{"command": "cat > fetch_joke.py << 'EOF'\nimport requests\nresponse = requests.get('https://official-joke-api.appspot.com/random_joke')\njoke = response.json()\nprint(f\"Setup: {joke['setup']}\")\nprint(f\"Punchline: {joke['punchline']}\")\nEOF"}
3. Run script
{"command": "python fetch_joke.py"}セッションはコマンド間で状態を維持するため、ステップ2で作成されたファイルはステップ3で利用できます。
bashツールを実装する
どのコマンドを実行するかはClaudeが決定します。それ以外のすべて、つまりシェルプロセス、タイムアウト、安全性チェックはアプリケーションが所有します。以下の手順は最小限の実装を示しています。
永続的なbashセッションを作成する
長寿命のbashプロセスを1つ起動し、すべてのコマンドをその中で実行します。生きているプロセスへのパイプはファイル終端を報告しないため、セッションは各コマンドの後に一意のセンチネル行を出力して、そのコマンドの出力がどこで終わるかを示します。
import subprocess import uuid class BashSession: """A bash process that stays alive between commands so state persists.""" def __init__(self): self.process = subprocess.Popen( ["/bin/bash"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, # interleave errors with output, in order start_new_session=True, # own process group: a timeout can kill every child text=True, ) def execute_command(self, command): """Run a command in the session and return its output.""" sentinel = f"__CLAUDE_BASH_DONE_{uuid.uuid4().hex}__" # unique per call self.process.stdin.write(f"{command}\necho {sentinel}\n") self.process.stdin.flush() output = [] for line in self.process.stdout: if sentinel in line: # this command's output is complete break output.append(line) return "".join(output) def restart(self): self.process.kill() self.process.wait() self.__init__() bash_session = BashSession() print(bash_session.execute_command("cd /tmp && pwd")) print(bash_session.execute_command("pwd")) # still /tmp: the session kept its stateセッションはstderrをstdoutとインターリーブするため、エラーメッセージは発生した場所に出力されます。この例では、完全な実装に必要なものが省略されています。コマンドがハングしたときにシェルとそれが起動したすべてのプロセスを終了し、セッションを再起動するタイムアウトです。コマンドタイムアウトを使用するのベストプラクティスで、これを追加する方法の1つを示しています。
Claudeのツール呼び出しを処理する
Claudeの応答からコマンドを抽出して実行します。
tool_results = [] for content in response.content: if content.type == "tool_use" and content.name == "bash": if content.input.get("restart"): bash_session.restart() result = "Bash session restarted" else: command = content.input.get("command") result = bash_session.execute_command(command) # 各tool_useブロックにつき1つのtool_resultを、すべて次のユーザーメッセージで返します tool_results.append( {"type": "tool_result", "tool_use_id": content.id, "content": result} )結果をClaudeに返す
同じ会話を継続する
userメッセージでtool_resultを送り返します。Claudeは同じセッションで別のコマンドをリクエストするか、回答を完了します。client = anthropic.Anthropic() response = client.messages.create( model="claude-opus-5-5", max_tokens=1024, tools=[{"type": "bash_20250124", "name": "bash"}], messages=[ {"role": "user", "content": "List all Python files in the current directory."}, { "role": "assistant", "content": [ { "type": "tool_use", "id": "toolu_01A09q90qw90lq917835lq9", "name": "bash", "input": {"command": "ls *.py"}, } ], }, { "role": "user", "content": [ { "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "analysis.py\nprocess_data.py\n", } ], }, ], ) print(response.content)stop_reasonがtool_useである間は、実行して返すサイクルを繰り返します。ループ全体については、クライアントツールからの結果の処理を参照してください。安全対策を実装する
検証と制限を追加します。ブロックリストではなく「allowlist」(許可リスト)を使用してください。ブロックリストは想定していなかったコマンドを見逃してしまいます。この例では、独立した単語として現れるシェル演算子も拒否します:
import shlex ALLOWED_COMMANDS = {"ls", "cat", "echo", "pwd", "grep", "find", "wc", "head", "tail"} SHELL_OPERATORS = {"&&", "||", "|", ";", "&", ">", "<", ">>"} def validate_command(command): # 明示的な許可リストにあるコマンドのみを許可 try: tokens = shlex.split(command) except ValueError: return False, "Could not parse command" if not tokens: return False, "Empty command" executable = tokens[0] if executable not in ALLOWED_COMMANDS: return False, f"Command '{executable}' is not in the allowlist" # 別々の単語として書かれたシェル演算子を拒否 for token in tokens[1:]: if token in SHELL_OPERATORS or token.startswith(("$", "`")): return False, f"Shell operator '{token}' is not allowed" return True, Noneこのチェックは明らかなミスを検知するためのトリップワイヤーであり、強制的な境界ではありません。このページの他の例で使用している、スペースで区切られた連結(
&&)、パイプ、リダイレクトを拒否します。cat data.txt|grep xのように単語にくっついた演算子は検出しません。トークナイザーがdata.txt|grepを1つのトークン内に保持するためです。アプリケーションがどのコマンドと演算子を許可するかを決めてください。本当の制御手段は隔離です。セッション全体をコンテナまたは仮想マシン内で実行してください(セキュリティを参照)。
エラーを処理する
コマンドが失敗したりセッションが壊れたりした場合は、何が起きたかをClaudeに伝えます。メッセージを tool_result のコンテンツとして返し、is_error を true に設定します。これによりツール呼び出しが失敗としてマークされます。is_errorによるエラー処理を参照してください。
コマンドの実行に時間がかかりすぎる場合:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "Error: command did not finish within 30 seconds",
"is_error": true
}
]
}コマンドが存在しない場合:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "bash: nonexistentcommand: command not found",
"is_error": true
}
]
}権限の問題がある場合:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "bash: /root/sensitive-file: Permission denied",
"is_error": true
}
]
}実装のベストプラクティスに従う
入力を待つコマンドのように決して終了しないコマンドは、センチネル行が届かないためセッションを永久にブロックします。すべてのコマンドに期限を設けてください。期限が過ぎたら、シェルとコマンドが起動したすべてのものを停止し、セッションを再起動します。
import concurrent.futures
import os
import signal
def execute_with_timeout(session, command, timeout=30):
"""Run a command in the session, replacing the session if the command hangs."""
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool:
future = pool.submit(session.execute_command, command)
try:
return future.result(timeout=timeout)
except concurrent.futures.TimeoutError:
# グループはシェルと、コマンドが起動したすべてのプロセスで構成されます
os.killpg(session.process.pid, signal.SIGKILL)
session.restart()
return f"Error: command did not finish within {timeout} seconds"このkillはハングしたコマンドとそれが起動したすべてのものを停止します。メッセージをエラーの tool_result として返してください(エラーを処理するを参照)。これによりツール呼び出しが失敗としてマークされます。
環境変数と作業ディレクトリを維持するために、bashセッションを永続的に保ちます。
# 同じセッションで実行されるコマンドは状態を維持します
commands = [
"cd /tmp",
"echo 'Hello' > test.txt",
"cat test.txt", # The session is still in /tmp
]トークン制限の問題を防ぐために、大きな出力を切り詰めます。
def truncate_output(output, max_lines=100):
lines = output.split("\n")
if len(lines) > max_lines:
truncated = "\n".join(lines[:max_lines])
return f"{truncated}\n\n... Output truncated ({len(lines)} total lines) ..."
return output監査証跡を残します。すべてのコマンドを1つのラッパー経由で実行し、実行前にコマンドを、完了後に出力を記録します。ハングしたりセッションを壊したりするコマンドでも記録が残ります。
import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s")
def execute_and_log(session, command):
"""Run a command in the session and keep an audit record of it."""
logging.info("command=%r", command)
output = session.execute_command(command)
logging.info("output=%r", output[:200]) # first 200 characters
return output記録はデフォルトで stderr に出力されます。保存するにはファイルまたはロギングパイプラインに向けてください。エンドユーザーや tool_use_id など、アプリケーション内で記録をリクエストに結び付けるものを含めてください。
セキュリティ
隔離に加えて、以下の制御を追加してください。
- コマンドを実行する前に、ブロックリストではなく許可リストで検証します。bashツールを実装するを参照してください。
- シェルプロセスにリソース制限(CPU、メモリ、ディスク)を設定します。たとえば
ulimitを使用します。 - 何が実行されたかを監査できるように、すべてのコマンドとその出力をログに記録します。
- Claudeに返す前に、出力から認証情報やその他のシークレットを削除します。
料金
bashツールの定義は、リクエストに以下の入力トークンを追加します。これは、いずれかのツールが存在する場合に常に適用されるモデルごとのツール使用システムプロンプトに加えて発生するものです。
| モデル | 追加の入力トークン |
|---|---|
| Claude Opus 5、Claude Opus 4.8、およびClaude Opus 4.7 | 325トークン |
| Claude Opus 4.6、Claude Sonnet 4.6、およびそれ以前 | 244トークン |
追加のトークンは以下によって消費されます。
- コマンド出力(stdout/stderr)
- エラーメッセージ
- 大きなファイルの内容
料金の詳細については、ツール使用の料金を参照してください。
一般的なパターン
開発ワークフロー
- テストの実行:
pytest && coverage report - プロジェクトのビルド:
npm install && npm run build - Git操作:
git status && git add . && git commit -m "message"
長時間実行されるエージェントワークフローでgitをチェックポイントおよびリカバリのメカニズムとして使用するガイダンスについては、状態管理のベストプラクティスを参照してください。
ファイル操作
- データの処理:
wc -l *.csv && ls -lh *.csv - ファイルの検索:
find . -name "*.py" | xargs grep "pattern" - バックアップの作成:
tar -czf backup.tar.gz ./data
システムタスク
- リソースの確認:
df -h && free -m - プロセス管理:
ps aux | grep python - 環境セットアップ:
export PATH=$PATH:/new/path && echo $PATH
制限事項
- 対話型コマンドは不可: セッションでは
vim、less、パスワードプロンプト、またはstdinで入力を待つコマンドは実行できません。 - GUIアプリケーションは不可: セッションはコマンドラインのみです。
- セッションのスコープ: bashセッションの状態はクライアント側にあります。ターン間でシェルセッションを維持する責任はアプリケーションにあります。
- 出力の制限: APIはツール結果を切り詰めません(サイズ超過のリクエストは拒否されます)。大きな出力はClaudeに返す前にアプリケーションで切り詰めてください。
- ストリーミングなし: 出力がClaudeに届くのは、アプリケーションが次のリクエストで
tool_resultを返したときのみです。
他のツールとの組み合わせ
bashツールはテキストエディタツールと相性が良いです。Claudeは一方のツールでファイルを編集し、もう一方のツールでそれを実行するコマンドをリクエストします。
次のステップ
テキストファイルを表示および変更して、コードのデバッグ、修正、改善を行います。
Claudeを外部ツールやAPIに接続します。ツールがどこで実行されるか、Claudeがいつツールを呼び出すか、どのツールがタスクに適しているかを確認してください。
Was this page helpful?