La herramienta bash es una herramienta de cliente: Claude no ejecuta los comandos por sí mismo. Cuando incluyes la herramienta en una solicitud, Claude responde con un bloque tool_use que indica el comando a ejecutar. Tu aplicación ejecuta ese comando en una sesión de bash que ella misma gestiona y devuelve la salida en un bloque tool_result.
Tu aplicación mantiene un único proceso de bash activo entre llamadas a la herramienta, de modo que el estado persiste entre comandos. El directorio de trabajo, las variables de entorno y cualquier archivo que un comando cree siguen estando disponibles para el siguiente comando.
La versión actual de la herramienta es bash_20250124. Para conocer la compatibilidad con modelos, los encabezados beta y la versión anterior, consulta Versiones de la herramienta. Para ver todas las herramientas proporcionadas por Anthropic, consulta la Referencia de herramientas.
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 responde con stop_reason: "tool_use" y un bloque tool_use que contiene el comando que tu aplicación debe ejecutar:
{
"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"
}
}
]
}Ejecuta input.command en tu sesión de bash y envía la salida de vuelta como un tool_result. Consulta Implementar la herramienta bash para ver el ciclo completo.
Cada llamada a la herramienta es un ciclo de ida y vuelta entre Claude y tu aplicación:
tool_use que contiene el command a ejecutar.tool_result.Claude también puede devolver varios bloques tool_use en una sola respuesta. Ejecútalos en orden en la misma sesión y devuelve todos los resultados en un único mensaje user. Consulta Uso de herramientas en paralelo.
La API no tiene estado. Nada de tu sesión de shell viaja entre solicitudes, por lo que tu aplicación decide cuándo comienza la sesión, cuánto tiempo dura y cuándo reiniciarla. Para ver el ciclo completo de solicitud y respuesta, consulta Gestionar llamadas a herramientas.
Una definición de la herramienta bash tiene dos campos obligatorios, type y name, y el name debe ser bash. La herramienta no tiene esquema: no proporcionas un input_schema, porque el esquema está integrado en el modelo de Claude y no se puede modificar. La siguiente tabla enumera los campos de entrada que Claude establece cuando llama a la herramienta.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
command | Sí* | El comando de bash a ejecutar |
restart | No | Establécelo en true para reiniciar la sesión de bash |
*Obligatorio a menos que se use restart
Para gestionar restart: true, termina el proceso de shell, inicia uno nuevo y devuelve un tool_result que confirme el reinicio. Una sesión reiniciada comienza limpia: el directorio de trabajo, las variables de entorno y cualquier proceso en ejecución desaparecen.
bash_20250124 es la versión actual de la herramienta y no requiere ningún encabezado beta. Todos los modelos desde Claude Sonnet 3.7 (retirado) en adelante la aceptan, incluidos todos los modelos actuales de Claude.
La versión original bash_20241022 forma parte de la beta de computer use, y la versión de Claude Sonnet 3.5 de octubre de 2024 (retirada) es el único modelo que la acepta. Las solicitudes que la usan necesitan el encabezado anthropic-beta: computer-use-2024-10-22, y los SDK la exponen solo en sus espacios de nombres beta. Las nuevas integraciones deben usar bash_20250124.
Claude puede encadenar comandos a lo largo de varias llamadas a la herramienta para completar una tarea de varios pasos:
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 sesión mantiene el estado entre comandos, por lo que los archivos creados en el paso 2 están disponibles en el paso 3.
Claude determina qué comando ejecutar. Tu aplicación es responsable de todo lo demás: el proceso de shell, el tiempo de espera y las comprobaciones de seguridad. Los siguientes pasos muestran una implementación mínima.
Crear una sesión de bash persistente
Inicia un único proceso de bash de larga duración y ejecuta cada comando dentro de él. Dado que una tubería hacia un proceso activo nunca informa de fin de archivo, la sesión imprime una línea centinela única después de cada comando para marcar dónde termina la salida de ese 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 sesión intercala stderr con stdout, de modo que los mensajes de error aparecen donde ocurrieron. El ejemplo omite lo que una implementación completa también necesita: un tiempo de espera que termine el shell y todos los procesos que inició cuando un comando se bloquea, y luego reinicie la sesión. La práctica recomendada Usar tiempos de espera para comandos muestra una forma de añadirlo.
Procesar las llamadas a herramientas de Claude
Extrae y ejecuta los comandos de las respuestas de 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 por cada bloque tool_use, todos devueltos en el siguiente mensaje de usuario
tool_results.append(
{"type": "tool_result", "tool_use_id": content.id, "content": result}
)Devolver el resultado a Claude
Envía el tool_result de vuelta en un mensaje user que continúe la misma conversación. Claude solicita otro comando en la misma sesión o finaliza su respuesta:
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)Repite el ciclo de ejecutar y devolver mientras stop_reason sea tool_use. Para ver el bucle completo, consulta Gestionar resultados de herramientas de cliente.
Implementar medidas de seguridad
Añade validación y restricciones. Usa una lista de permitidos en lugar de una lista de bloqueados: una lista de bloqueados pasa por alto cualquier comando que no haya anticipado. El ejemplo también rechaza los operadores de shell que aparecen como palabras separadas:
import shlex
ALLOWED_COMMANDS = {"ls", "cat", "echo", "pwd", "grep", "find", "wc", "head", "tail"}
SHELL_OPERATORS = {"&&", "||", "|", ";", "&", ">", "<", ">>"}
def validate_command(command):
# Permitir solo comandos de una lista de permitidos explícita
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"
# Rechazar operadores de shell escritos como palabras separadas
for token in tokens[1:]:
if token in SHELL_OPERATORS or token.startswith(("$", "`")):
return False, f"Shell operator '{token}' is not allowed"
return True, NoneEsta comprobación es una alerta para errores obvios, no un límite de cumplimiento. Rechaza el encadenamiento con espacios (&&), las tuberías y la redirección que usan los otros ejemplos de esta página. No detecta un operador pegado a una palabra, como cat data.txt|grep x, porque el tokenizador mantiene data.txt|grep dentro de un solo token. Decide qué comandos y operadores permite tu aplicación. El control real es el aislamiento: ejecuta toda la sesión dentro de un contenedor o una máquina virtual (consulta Seguridad).
Cuando un comando falla o la sesión se rompe, informa a Claude de lo que ocurrió. Devuelve el mensaje como contenido del tool_result y establece is_error en true, lo que marca la llamada a la herramienta como fallida. Consulta Gestionar errores con is_error.
Además del aislamiento, añade estos controles:
ulimit.La definición de la herramienta bash agrega los siguientes tokens de entrada a tu solicitud. Esto es adicional a la indicación del sistema de uso de herramientas por modelo que se aplica siempre que haya alguna herramienta presente.
| Modelo | Tokens de entrada adicionales |
|---|---|
| Claude Opus 5, Claude Opus 4.8 y Claude Opus 4.7 | 325 tokens |
| Claude Opus 4.6, Claude Sonnet 4.6 y anteriores | 244 tokens |
Los tokens adicionales son consumidos por:
Consulta precios del uso de herramientas para obtener detalles completos sobre los precios.
pytest && coverage reportnpm install && npm run buildgit status && git add . && git commit -m "message"Para obtener orientación sobre el uso de git como mecanismo de puntos de control y recuperación en flujos de trabajo de agentes de larga duración, consulta las prácticas recomendadas de gestión de estado.
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, solicitudes de contraseña ni ningún comando que espere entrada en stdin.tool_result en la siguiente solicitud.La herramienta bash se combina bien con la herramienta de editor de texto: Claude edita un archivo con una herramienta y solicita el comando que lo ejecuta con la otra.
Visualiza y modifica archivos de texto para depurar, corregir y mejorar código.
Conecta Claude con herramientas y API externas. Descubre dónde se ejecutan las herramientas, cuándo las llama Claude y qué herramienta se adapta a tu tarea.
Was this page helpful?