Bash 工具
讓 Claude 請求 shell 指令,由您的應用程式在持久的 bash 工作階段中執行,並以工具結果的形式回傳。
Bash 工具是一種 client tool(用戶端工具):Claude 本身不會執行指令。當您在請求中包含此工具時,Claude 會回覆一個 tool_use 區塊,指明要執行的指令。您的應用程式在其擁有的 bash 工作階段中執行該指令,並在 tool_result 區塊中回傳輸出。
您的應用程式會在多次工具呼叫之間保持一個 bash 程序持續運作,因此狀態會在指令之間保留。工作目錄、環境變數,以及指令所建立的任何檔案,在下一個指令執行時仍然存在。
此工具的目前版本為 bash_20250124。關於模型支援、beta 標頭以及較早的版本,請參閱工具版本。關於所有 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 與您的應用程式之間的一次往返:
- Claude 回傳一個包含要執行之
command的tool_use區塊。 - 您的應用程式在其 bash 工作階段中執行該指令。
- 您的應用程式將指令的輸出(stdout 與 stderr 一併)以
tool_result區塊回傳給 Claude。 - Claude 會在同一個工作階段中請求另一個指令,或以文字回應。
Claude 也可能在一次回應中回傳多個 tool_use 區塊。請在同一個工作階段中依序執行它們,並在一則 user 訊息中回傳所有結果。請參閱平行工具使用。
API 是無狀態的。您的 shell 工作階段的任何資訊都不會在請求之間傳遞,因此由您的應用程式決定工作階段何時開始、存活多久,以及何時重新啟動。完整的請求與回應週期請參閱處理工具呼叫。
參數
Bash 工具定義有兩個必填欄位:type 與 name,且 name 必須為 bash。此工具沒有結構描述(schema-less):您不需要提供 input_schema,因為結構描述已內建於 Claude 的模型中且無法修改。下表列出 Claude 呼叫此工具時所設定的輸入欄位。
| 參數 | 必填 | 說明 |
|---|---|---|
command | 是* | 要執行的 bash 指令 |
restart | 否 | 設為 true 以重新啟動 bash 工作階段 |
*除非使用 restart,否則為必填
要處理 restart: true,請終止 shell 程序、啟動一個新的程序,並回傳一個確認已重新啟動的 tool_result。重新啟動後的工作階段是全新的:工作目錄、環境變數以及任何執行中的程序都會消失。
執行指令:
{
"command": "ls -la *.py"
}重新啟動工作階段:
{
"restart": true
}工具版本
bash_20250124 是此工具的目前版本,不需要 beta 標頭。從 Claude Sonnet 3.7(已退役)起的每個模型都接受它,包括所有目前的 Claude 模型。
原始的 bash_20241022 版本僅適用於 2024 年 10 月的 Claude Sonnet 3.5 模型(已退役)。使用它的請求需要 anthropic-beta: computer-use-2024-10-22 標頭,且 SDK 僅在其 beta 命名空間中提供它。新的整合應使用 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 決定要執行哪個指令。其餘一切由您的應用程式負責:shell 程序、逾時以及安全檢查。以下步驟展示一個最小實作。
建立持久的 bash 工作階段
啟動一個長時間存活的 bash 程序,並在其中執行每個指令。由於連接到存活程序的管道永遠不會回報檔案結尾(end-of-file),工作階段會在每個指令之後印出一行唯一的哨兵(sentinel)行,以標記該指令輸出的結束位置:
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 交錯輸出,因此錯誤訊息會出現在其發生的位置。此範例省略了完整實作還需要的部分:一個逾時機制,當指令卡住時終止 shell 及其啟動的所有程序,然後重新啟動工作階段。使用指令逾時最佳實務展示了一種加入它的方式。
處理 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 區塊對應一個 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)而非封鎖清單(blocklist):封鎖清單會遺漏任何未預料到的命令。此範例也會拒絕以獨立單字形式出現的 shell 運算子:
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" # 拒絕以獨立單字形式撰寫的 shell 運算子 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此檢查是針對明顯錯誤的絆線(tripwire),而非強制執行的邊界。它會拒絕本頁其他範例所使用的以空格分隔的串接(
&&)、管道與重新導向。它無法捕捉黏附在單字上的運算子,例如cat data.txt|grep x,因為分詞器會將data.txt|grep保留在同一個 token 內。請決定您的應用程式允許哪些指令與運算子。真正的控制在於隔離:在容器或虛擬機器中執行整個工作階段(請參閱安全性)。
處理錯誤
當指令失敗或工作階段中斷時,請告訴 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
}
]
}遵循實作最佳實務
永遠不會結束的指令(例如等待輸入的指令)會永久阻塞工作階段,因為它的哨兵行永遠不會到達。請為每個指令設定期限。當期限過後,停止 shell 以及該指令啟動的所有程序,然後重新啟動工作階段:
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:
# 此群組包含 shell 以及該指令所啟動的每個行程
os.killpg(session.process.pid, signal.SIGKILL)
session.restart()
return f"Error: command did not finish within {timeout} seconds"終止動作會停止卡住的指令及其啟動的所有程序。將訊息作為錯誤的 tool_result 回傳(請參閱處理錯誤),以將該工具呼叫標記為失敗。
保持 bash 工作階段持久,以維持環境變數與工作目錄:
# 在同一工作階段中執行的指令會保留狀態
commands = [
"cd /tmp",
"echo 'Hello' > test.txt",
"cat test.txt", # The session is still in /tmp
]截斷大量輸出以避免 token 限制問題:
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保留稽核軌跡。將每個指令導向同一個包裝函式,在指令執行前記錄指令,並在完成後記錄輸出。即使指令卡住或使工作階段中斷,仍會留下記錄:
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 工具。
- 對 shell 程序設定資源限制(CPU、記憶體與磁碟),例如使用
ulimit。 - 記錄每個指令及其輸出,以便稽核執行過的內容。
- 在將輸出回傳給 Claude 之前,遮蔽其中的憑證與其他機密資訊。
定價
bash 工具定義會為您的請求增加以下輸入 token。這是在每個模型的工具使用系統提示之外額外增加的,只要存在任何工具,該系統提示便會適用。
| 模型 | 額外輸入 token |
|---|---|
| Claude Opus 5、Claude Opus 4.8 與 Claude Opus 4.7 | 325 個 token |
| Claude Opus 4.6、Claude Sonnet 4.6 及更早版本 | 244 個 token |
以下項目會消耗額外的 token:
- 指令輸出(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 工作階段狀態位於用戶端。您的應用程式負責在回合之間維持 shell 工作階段。
- 輸出限制: API 不會截斷工具結果(過大的請求會被拒絕)。請在您的應用程式中截斷大量輸出後再回傳給 Claude。
- 不支援串流: 只有當您的應用程式在下一個請求中回傳
tool_result時,輸出才會送達 Claude。
與其他工具結合
Bash 工具與文字編輯器工具搭配良好:Claude 使用其中一個工具編輯檔案,並使用另一個工具請求執行該檔案的指令。
後續步驟
檢視與修改文字檔案,以除錯、修正並改進程式碼。
將 Claude 連接至外部工具與 API。了解工具在何處執行、Claude 何時呼叫它們,以及哪種工具適合您的任務。
Was this page helpful?