Das Bash-Tool ist ein Client-Tool: Claude führt selbst keine Befehle aus. Wenn du das Tool in eine Anfrage einbindest, antwortet Claude mit einem tool_use-Block, der den auszuführenden Befehl benennt. Deine Anwendung führt diesen Befehl in einer eigenen Bash-Sitzung aus und gibt die Ausgabe in einem tool_result-Block zurück.
Deine Anwendung hält einen Bash-Prozess über mehrere Tool-Aufrufe hinweg am Leben, sodass der Zustand zwischen den Befehlen erhalten bleibt. Das Arbeitsverzeichnis, Umgebungsvariablen und alle Dateien, die ein Befehl erstellt, sind für den nächsten Befehl weiterhin vorhanden.
Die aktuelle Version des Tools ist bash_20250124. Informationen zur Modellunterstützung, zu Beta-Headern und zur früheren Version findest du unter Tool-Versionen. Alle von Anthropic bereitgestellten Tools findest du in der Tool-Referenz.
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-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 antwortet mit stop_reason: "tool_use" und einem tool_use-Block, der den Befehl enthält, den deine Anwendung ausführen soll:
{
"id": "msg_01XAbCDeFgHiJkLmNoPQrStU",
"model": "claude-opus-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"
}
}
]
}Führe input.command in deiner Bash-Sitzung aus und sende die Ausgabe als tool_result zurück. Siehe Das Bash-Tool implementieren für den vollständigen Ablauf.
Jeder Tool-Aufruf ist ein Hin- und Rückweg zwischen Claude und deiner Anwendung:
tool_use-Block zurück, der den auszuführenden command enthält.tool_result-Block an Claude zurück.Claude kann auch mehrere tool_use-Blöcke in einer Antwort zurückgeben. Führe sie der Reihe nach in derselben Sitzung aus und gib alle Ergebnisse in einer user-Nachricht zurück. Siehe Parallele Tool-Nutzung.
Die API ist zustandslos. Nichts von deiner Shell-Sitzung wird zwischen Anfragen übertragen, daher entscheidet deine Anwendung, wann die Sitzung beginnt, wie lange sie läuft und wann sie neu gestartet wird. Den vollständigen Anfrage- und Antwortzyklus findest du unter Tool-Aufrufe verarbeiten.
Eine Bash-Tool-Definition hat zwei Pflichtfelder, type und name, und name muss bash sein. Das Tool ist schemalos: Du gibst kein input_schema an, da das Schema in Claudes Modell integriert ist und nicht geändert werden kann. Die folgende Tabelle listet die Eingabefelder auf, die Claude beim Aufruf des Tools setzt.
| Parameter | Erforderlich | Beschreibung |
|---|---|---|
command | Ja* | Der auszuführende Bash-Befehl |
restart | Nein | Auf true setzen, um die Bash-Sitzung neu zu starten |
*Erforderlich, außer bei Verwendung von restart
Um restart: true zu verarbeiten, beende den Shell-Prozess, starte einen neuen und gib ein tool_result zurück, das den Neustart bestätigt. Eine neu gestartete Sitzung beginnt bei null: Das Arbeitsverzeichnis, Umgebungsvariablen und alle laufenden Prozesse sind weg.
bash_20250124 ist die aktuelle Version des Tools und erfordert keinen Beta-Header. Jedes Modell ab Claude Sonnet 3.7 (eingestellt) akzeptiert sie, einschließlich aller aktuellen Claude-Modelle.
Die ursprüngliche Version bash_20241022 ist Teil der Computer-Use-Beta, und die Claude Sonnet 3.5-Version vom Oktober 2024 (eingestellt) ist das einzige Modell, das sie akzeptiert. Anfragen, die sie verwenden, benötigen den Header anthropic-beta: computer-use-2024-10-22, und die SDKs stellen sie nur in ihren Beta-Namespaces bereit. Neue Integrationen sollten bash_20250124 verwenden.
Claude kann Befehle über mehrere Tool-Aufrufe hinweg verketten, um eine mehrstufige Aufgabe abzuschließen:
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"}Die Sitzung behält den Zustand zwischen den Befehlen bei, sodass in Schritt 2 erstellte Dateien in Schritt 3 verfügbar sind.
Claude bestimmt, welcher Befehl ausgeführt werden soll. Deine Anwendung ist für alles andere verantwortlich: den Shell-Prozess, das Timeout und die Sicherheitsprüfungen. Die folgenden Schritte zeigen eine minimale Implementierung.
Eine persistente Bash-Sitzung erstellen
Starte einen langlebigen Bash-Prozess und führe jeden Befehl darin aus. Da eine Pipe zu einem laufenden Prozess niemals ein Dateiende meldet, gibt die Sitzung nach jedem Befehl eine eindeutige Sentinel-Zeile aus, um zu markieren, wo die Ausgabe dieses Befehls endet:
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 stateDie Sitzung verschachtelt stderr mit stdout, sodass Fehlermeldungen dort landen, wo sie aufgetreten sind. Das Beispiel lässt aus, was eine vollständige Implementierung ebenfalls benötigt: ein Timeout, das die Shell und jeden von ihr gestarteten Prozess beendet, wenn ein Befehl hängt, und dann die Sitzung neu startet. Die Best Practice Befehls-Timeouts verwenden zeigt eine Möglichkeit, dies hinzuzufügen.
Claudes Tool-Aufrufe verarbeiten
Extrahiere Befehle aus Claudes Antworten und führe sie aus:
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)
# Ein tool_result pro tool_use-Block, alle in der nächsten User-Nachricht zurückgegeben
tool_results.append(
{"type": "tool_result", "tool_use_id": content.id, "content": result}
)Das Ergebnis an Claude zurückgeben
Sende das tool_result in einer user-Nachricht zurück, die dieselbe Konversation fortsetzt. Claude fordert entweder einen weiteren Befehl in derselben Sitzung an oder beendet seine Antwort:
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-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)Wiederhole den Ausführen-und-Zurückgeben-Zyklus, solange stop_reason den Wert tool_use hat. Die vollständige Schleife findest du unter Ergebnisse von Client-Tools verarbeiten.
Sicherheitsmaßnahmen implementieren
Füge Validierung und Einschränkungen hinzu. Verwende eine Allowlist statt einer Blocklist: Eine Blocklist übersieht jeden Befehl, den sie nicht vorhergesehen hat. Das Beispiel lehnt auch Shell-Operatoren ab, die als separate Wörter erscheinen:
import shlex
ALLOWED_COMMANDS = {"ls", "cat", "echo", "pwd", "grep", "find", "wc", "head", "tail"}
SHELL_OPERATORS = {"&&", "||", "|", ";", "&", ">", "<", ">>"}
def validate_command(command):
# Erlaube nur Befehle aus einer expliziten Allowlist
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"
# Lehne Shell-Operatoren ab, die als separate Wörter geschrieben sind
for token in tokens[1:]:
if token in SHELL_OPERATORS or token.startswith(("$", "`")):
return False, f"Shell operator '{token}' is not allowed"
return True, NoneDiese Prüfung ist ein Stolperdraht für offensichtliche Fehler, keine Durchsetzungsgrenze. Sie lehnt die durch Leerzeichen getrennte Verkettung (&&), Pipes und Umleitungen ab, die die anderen Beispiele auf dieser Seite verwenden. Sie erkennt keinen Operator, der an ein Wort geklebt ist, wie etwa cat data.txt|grep x, weil der Tokenizer data.txt|grep in einem Token belässt. Entscheide, welche Befehle und Operatoren deine Anwendung zulässt. Die eigentliche Kontrolle ist Isolation: Führe die gesamte Sitzung in einem Container oder einer virtuellen Maschine aus (siehe Sicherheit).
Wenn ein Befehl fehlschlägt oder die Sitzung abbricht, teile Claude mit, was passiert ist. Gib die Nachricht als tool_result-Inhalt zurück und setze is_error auf true, wodurch der Tool-Aufruf als fehlgeschlagen markiert wird. Siehe Fehler mit is_error behandeln.
Füge über die Isolation hinaus diese Kontrollen hinzu:
ulimit.Die Bash-Tool-Definition fügt deiner Anfrage die folgenden Input-Token hinzu. Dies kommt zusätzlich zum modellspezifischen System-Prompt für Tool-Nutzung hinzu, der immer dann gilt, wenn ein Tool vorhanden ist.
| Modell | Zusätzliche Input-Token |
|---|---|
| Claude Opus 5, Claude Opus 4.8 und Claude Opus 4.7 | 325 Token |
| Claude Opus 4.6, Claude Sonnet 4.6 und früher | 244 Token |
Zusätzliche Token werden verbraucht durch:
Siehe Preise für Tool-Nutzung für vollständige Preisdetails.
pytest && coverage reportnpm install && npm run buildgit status && git add . && git commit -m "message"Hinweise zur Verwendung von Git als Checkpoint- und Wiederherstellungsmechanismus in langlaufenden Agenten-Workflows findest du unter Best Practices für die Zustandsverwaltung.
wc -l *.csv && ls -lh *.csvfind . -name "*.py" | xargs grep "pattern"tar -czf backup.tar.gz ./datadf -h && free -mps aux | grep pythonexport PATH=$PATH:/new/path && echo $PATHvim, less, Passwortabfragen oder andere Befehle, die auf Eingaben über stdin warten, nicht ausführen.tool_result in der nächsten Anfrage zurückgibt.Das Bash-Tool lässt sich gut mit dem Text-Editor-Tool kombinieren: Claude bearbeitet eine Datei mit dem einen Tool und fordert mit dem anderen den Befehl an, der sie ausführt.
Textdateien anzeigen und bearbeiten, um Code zu debuggen, zu korrigieren und zu verbessern.
Verbinde Claude mit externen Tools und APIs. Erfahre, wo Tools ausgeführt werden, wann Claude sie aufruft und welches Tool zu deiner Aufgabe passt.
Was this page helpful?