Bash tool
Consenti a Claude di richiedere comandi shell che la tua applicazione esegue in una sessione bash persistente e restituisce come risultati degli strumenti.
Il bash tool è un client tool: Claude non esegue i comandi da solo. Quando includi lo strumento in una richiesta, Claude risponde con un blocco tool_use che indica il comando da eseguire. La tua applicazione esegue quel comando in una sessione bash che possiede e restituisce l'output in un blocco tool_result.
La tua applicazione mantiene attivo un processo bash tra le chiamate agli strumenti, quindi lo stato persiste tra i comandi. La directory di lavoro, le variabili d'ambiente e qualsiasi file creato da un comando sono ancora presenti per il comando successivo.
La versione attuale dello strumento è bash_20250124. Per il supporto dei modelli, i beta header e la versione precedente, consulta Versioni degli strumenti. Per tutti gli strumenti forniti da Anthropic, consulta il Riferimento degli strumenti.
Casi d'uso
- Flussi di lavoro di sviluppo: Esegui comandi di build, test e strumenti di sviluppo
- Automazione di sistema: Esegui script, gestisci file, automatizza attività
- Elaborazione dati: Elabora file, esegui script di analisi, gestisci dataset
- Configurazione dell'ambiente: Installa pacchetti, configura ambienti
Avvio rapido
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 risponde con stop_reason: "tool_use" e un blocco tool_use che contiene il comando che la tua applicazione deve eseguire:
{
"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"
}
}
]
}Esegui input.command nella tua sessione bash e invia l'output come tool_result. Consulta Implementare il bash tool per il ciclo completo.
Come funziona
Ogni chiamata allo strumento è un ciclo tra Claude e la tua applicazione:
- Claude restituisce un blocco
tool_usecontenente ilcommandda eseguire. - La tua applicazione esegue il comando nella sua sessione bash.
- La tua applicazione restituisce l'output del comando, stdout e stderr insieme, a Claude in un blocco
tool_result. - Claude richiede un altro comando nella stessa sessione oppure risponde con del testo.
Claude può anche restituire diversi blocchi tool_use in una sola risposta. Eseguili in ordine nella stessa sessione e restituisci tutti i risultati in un unico messaggio user. Consulta Uso parallelo degli strumenti.
L'API è stateless. Nulla della tua sessione shell viaggia tra le richieste, quindi la tua applicazione decide quando inizia la sessione, quanto dura e quando riavviarla. Per il ciclo completo di richiesta e risposta, consulta Gestire le chiamate agli strumenti.
Parametri
Una definizione del bash tool ha due campi obbligatori, type e name, e il name deve essere bash. Lo strumento è privo di schema: non fornisci un input_schema, perché lo schema è integrato nel modello di Claude e non può essere modificato. La tabella seguente elenca i campi di input che Claude imposta quando chiama lo strumento.
| Parametro | Obbligatorio | Descrizione |
|---|---|---|
command | Sì* | Il comando bash da eseguire |
restart | No | Imposta su true per riavviare la sessione bash |
*Obbligatorio a meno che non si usi restart
Per gestire restart: true, termina il processo shell, avviane uno nuovo e restituisci un tool_result che conferma il riavvio. Una sessione riavviata parte pulita: la directory di lavoro, le variabili d'ambiente e qualsiasi processo in esecuzione sono scomparsi.
Esegui un comando:
{
"command": "ls -la *.py"
}Riavvia la sessione:
{
"restart": true
}Versioni degli strumenti
bash_20250124 è la versione attuale dello strumento e non richiede alcun beta header. Ogni modello da Claude Sonnet 3.7 (ritirato) in poi lo accetta, inclusi tutti i modelli Claude attuali.
La versione originale bash_20241022 funziona solo con il modello Claude Sonnet 3.5 di ottobre 2024 (ritirato). Le richieste che la utilizzano necessitano dell'header anthropic-beta: computer-use-2024-10-22, e gli SDK la espongono solo nei loro namespace beta. Le nuove integrazioni dovrebbero usare bash_20250124.
Esempio: Automazione multi-step
Claude può concatenare comandi tra le chiamate agli strumenti per completare un'attività multi-step:
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"}La sessione mantiene lo stato tra i comandi, quindi i file creati nel passaggio 2 sono disponibili nel passaggio 3.
Implementare il bash tool
Claude determina quale comando eseguire. La tua applicazione possiede tutto il resto: il processo shell, il timeout e i controlli di sicurezza. I passaggi seguenti mostrano un'implementazione minima.
Crea una sessione bash persistente
Avvia un processo bash di lunga durata ed esegui ogni comando al suo interno. Poiché una pipe verso un processo attivo non segnala mai la fine del file, la sessione stampa una riga sentinella univoca dopo ogni comando per segnare dove termina l'output di quel comando:
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 stateLa sessione intercala stderr con stdout, quindi i messaggi di errore compaiono dove si sono verificati. L'esempio tralascia ciò di cui un'implementazione completa ha anche bisogno: un timeout che termina la shell e ogni processo che ha avviato quando un comando si blocca, quindi riavvia la sessione. La best practice Usa i timeout dei comandi mostra un modo per aggiungerlo.
Elabora le chiamate agli strumenti di Claude
Estrai ed esegui i comandi dalle risposte di 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) # Un tool_result per ogni blocco tool_use, tutti restituiti nel messaggio utente successivo tool_results.append( {"type": "tool_result", "tool_use_id": content.id, "content": result} )Restituisci il risultato a Claude
Invia il
tool_resultin un messaggiouserche continua la stessa conversazione. Claude richiede un altro comando nella stessa sessione oppure completa la sua risposta: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)Ripeti il ciclo di esecuzione e restituzione finché
stop_reasonètool_use. Per il ciclo completo, consulta Gestire i risultati dei client tool.Implementa misure di sicurezza
Aggiungi validazione e restrizioni. Usa una allowlist anziché una blocklist: una blocklist non rileva alcun comando che non ha previsto. L'esempio rifiuta anche gli operatori shell che compaiono come parole separate:
import shlex ALLOWED_COMMANDS = {"ls", "cat", "echo", "pwd", "grep", "find", "wc", "head", "tail"} SHELL_OPERATORS = {"&&", "||", "|", ";", "&", ">", "<", ">>"} def validate_command(command): # Consenti solo i comandi da un elenco di autorizzazioni esplicito 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" # Rifiuta gli operatori della shell scritti come parole separate for token in tokens[1:]: if token in SHELL_OPERATORS or token.startswith(("$", "`")): return False, f"Shell operator '{token}' is not allowed" return True, NoneQuesto controllo è un campanello d'allarme per errori evidenti, non un confine di applicazione. Rifiuta il concatenamento con spazi (
&&), le pipe e il reindirizzamento che gli altri esempi in questa pagina utilizzano. Non rileva un operatore incollato a una parola, comecat data.txt|grep x, perché il tokenizer mantienedata.txt|grepall'interno di un unico token. Decidi quali comandi e operatori la tua applicazione consente. Il vero controllo è l'isolamento: esegui l'intera sessione all'interno di un container o di una macchina virtuale (consulta Sicurezza).
Gestire gli errori
Quando un comando fallisce o la sessione si interrompe, comunica a Claude cosa è successo. Restituisci il messaggio come contenuto del tool_result e imposta is_error su true, il che contrassegna la chiamata allo strumento come fallita. Consulta Gestire gli errori con is_error.
Se un comando impiega troppo tempo per essere eseguito:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "Error: command did not finish within 30 seconds",
"is_error": true
}
]
}Se un comando non esiste:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "bash: nonexistentcommand: command not found",
"is_error": true
}
]
}Se ci sono problemi di permessi:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "bash: /root/sensitive-file: Permission denied",
"is_error": true
}
]
}Segui le best practice di implementazione
Un comando che non termina mai, come uno che attende input, blocca la sessione per sempre perché la sua riga sentinella non arriva mai. Assegna a ogni comando una scadenza. Quando la scadenza passa, arresta la shell e tutto ciò che il comando ha avviato, quindi riavvia la sessione:
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:
# Il gruppo è la shell e ogni processo avviato dal comando
os.killpg(session.process.pid, signal.SIGKILL)
session.restart()
return f"Error: command did not finish within {timeout} seconds"Il kill arresta il comando bloccato e tutto ciò che ha avviato. Restituisci il messaggio come tool_result di errore (consulta Gestire gli errori), il che contrassegna la chiamata allo strumento come fallita.
Mantieni la sessione bash persistente per conservare le variabili d'ambiente e la directory di lavoro:
# I comandi eseguiti nella stessa sessione mantengono lo stato
commands = [
"cd /tmp",
"echo 'Hello' > test.txt",
"cat test.txt", # The session is still in /tmp
]Tronca gli output di grandi dimensioni per prevenire problemi di limite di 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 outputMantieni una traccia di audit. Instrada ogni comando attraverso un unico wrapper che registra il comando prima che venga eseguito e l'output dopo che è terminato. Un comando che si blocca o interrompe la sessione lascia comunque una traccia:
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 outputLe tracce vanno su stderr per impostazione predefinita; indirizzale verso un file o la tua pipeline di logging per conservarle. Includi qualsiasi cosa colleghi la traccia alla richiesta nella tua applicazione, come l'utente finale e il tool_use_id.
Sicurezza
Oltre all'isolamento, aggiungi questi controlli:
- Valida i comandi prima di eseguirli, con una allowlist anziché una blocklist. Consulta Implementare il bash tool.
- Imposta limiti di risorse sul processo shell (CPU, memoria e disco), ad esempio con
ulimit. - Registra ogni comando e il suo output in modo da poter verificare cosa è stato eseguito.
- Oscura le credenziali e altri segreti dall'output prima di restituirlo a Claude.
Prezzi
La definizione dello strumento bash aggiunge i seguenti token di input alla tua richiesta. Questo si aggiunge al prompt di sistema per l'uso degli strumenti specifico per modello, che si applica ogni volta che è presente uno strumento qualsiasi.
| Modello | Token di input aggiuntivi |
|---|---|
| Claude Opus 5, Claude Opus 4.8 e Claude Opus 4.7 | 325 token |
| Claude Opus 4.6, Claude Sonnet 4.6 e precedenti | 244 token |
Token aggiuntivi vengono consumati da:
- Output dei comandi (stdout/stderr)
- Messaggi di errore
- Contenuti di file di grandi dimensioni
Consulta i prezzi dell'uso degli strumenti per i dettagli completi sui prezzi.
Pattern comuni
Flussi di lavoro di sviluppo
- Esecuzione di test:
pytest && coverage report - Build di progetti:
npm install && npm run build - Operazioni Git:
git status && git add . && git commit -m "message"
Per indicazioni sull'uso di git come meccanismo di checkpoint e ripristino nei flussi di lavoro degli agenti di lunga durata, consulta le best practice per la gestione dello stato.
Operazioni sui file
- Elaborazione dati:
wc -l *.csv && ls -lh *.csv - Ricerca di file:
find . -name "*.py" | xargs grep "pattern" - Creazione di backup:
tar -czf backup.tar.gz ./data
Attività di sistema
- Controllo delle risorse:
df -h && free -m - Gestione dei processi:
ps aux | grep python - Configurazione dell'ambiente:
export PATH=$PATH:/new/path && echo $PATH
Limitazioni
- Nessun comando interattivo: La sessione non può eseguire
vim,less, prompt di password o qualsiasi comando che attende input su stdin. - Nessuna applicazione GUI: La sessione è solo a riga di comando.
- Ambito della sessione: Lo stato della sessione bash è lato client. La tua applicazione è responsabile del mantenimento della sessione shell tra i turni.
- Limiti di output: L'API non tronca i risultati degli strumenti (una richiesta di dimensioni eccessive viene rifiutata). Tronca gli output di grandi dimensioni nella tua applicazione prima di restituirli a Claude.
- Nessuno streaming: L'output raggiunge Claude solo quando la tua applicazione restituisce il
tool_resultnella richiesta successiva.
Combinazione con altri strumenti
Il bash tool si abbina bene con il Text editor tool: Claude modifica un file con uno strumento e richiede il comando che lo esegue con l'altro.
Prossimi passi
Visualizza e modifica file di testo per eseguire il debug, correggere e migliorare il codice.
Connetti Claude a strumenti e API esterni. Scopri dove vengono eseguiti gli strumenti, quando Claude li chiama e quale strumento si adatta alla tua attività.
Was this page helpful?