File: bash-tool.md | Updated: 11/15/2025
Agent Skills are now available! Learn more about extending Claude's capabilities with Agent Skills .
English
Search...
Ctrl K
Search...
Navigation
Tools
Bash tool
Home Developer Guide API Reference Model Context Protocol (MCP) Resources Release Notes
On this page
The bash tool enables Claude to execute shell commands in a persistent bash session, allowing system operations, script execution, and command-line automation.
The bash tool provides Claude with:
| Model | Tool Version |
| --- | --- |
| Claude 4 models and Sonnet 3.7 (deprecated<br>) | bash_20250124 |
Older tool versions are not guaranteed to be backwards-compatible with newer models. Always use the tool version that corresponds to your model version.
Python
Shell
Copy
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[\
{\
"type": "bash_20250124",\
"name": "bash"\
}\
],
messages=[\
{"role": "user", "content": "List all Python files in the current directory."}\
]
)
The bash tool maintains a persistent session:
| Parameter | Required | Description |
| --- | --- | --- |
| command | Yes* | The bash command to run |
| restart | No | Set to true to restart the bash session |
*Required unless using restartExample usage
Copy
// Run a command
{
"command": "ls -la *.py"
}
// Restart the session
{
"restart": true
}
Claude can chain commands to complete complex tasks:
Copy
# 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"}
The session maintains state between commands, so files created in step 2 are available in step 3.
The bash tool is implemented as a schema-less tool. When using this tool, you donβt need to provide an input schema as with other tools; the schema is built into Claudeβs model and canβt be modified.
1
Set up a bash environment
Create a persistent bash session that Claude can interact with:
Copy
import subprocess
import threading
import queue
class BashSession:
def __init__(self):
self.process = subprocess.Popen(
['/bin/bash'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
bufsize=0
)
self.output_queue = queue.Queue()
self.error_queue = queue.Queue()
self._start_readers()
2
Handle command execution
Create a function to execute commands and capture output:
Copy
def execute_command(self, command):
# Send command to bash
self.process.stdin.write(command + '\n')
self.process.stdin.flush()
# Capture output with timeout
output = self._read_output(timeout=10)
return output
3
Process Claude's tool calls
Extract and execute commands from Claudeβs responses:
Copy
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)
# Return result to Claude
tool_result = {
"type": "tool_result",
"tool_use_id": content.id,
"content": result
}
4
Implement safety measures
Add validation and restrictions:
Copy
def validate_command(command):
# Block dangerous commands
dangerous_patterns = ['rm -rf /', 'format', ':(){:|:&};:']
for pattern in dangerous_patterns:
if pattern in command:
return False, f"Command contains dangerous pattern: {pattern}"
# Add more validation as needed
return True, None
Handle errors
When implementing the bash tool, handle various error scenarios:
Command execution timeout
If a command takes too long to execute:
Copy
{
"role": "user",
"content": [\
{\
"type": "tool_result",\
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",\
"content": "Error: Command timed out after 30 seconds",\
"is_error": true\
}\
]
}
Command not found
If a command doesnβt exist:
Copy
{
"role": "user",
"content": [\
{\
"type": "tool_result",\
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",\
"content": "bash: nonexistentcommand: command not found",\
"is_error": true\
}\
]
}
Permission denied
If there are permission issues:
Copy
{
"role": "user",
"content": [\
{\
"type": "tool_result",\
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",\
"content": "bash: /root/sensitive-file: Permission denied",\
"is_error": true\
}\
]
}
Follow implementation best practices
Use command timeouts
Implement timeouts to prevent hanging commands:
Copy
def execute_with_timeout(command, timeout=30):
try:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
timeout=timeout
)
return result.stdout + result.stderr
except subprocess.TimeoutExpired:
return f"Command timed out after {timeout} seconds"
Maintain session state
Keep the bash session persistent to maintain environment variables and working directory:
Copy
# Commands run in the same session maintain state
commands = [\
"cd /tmp",\
"echo 'Hello' > test.txt",\
"cat test.txt" # This works because we're still in /tmp\
]
Handle large outputs
Truncate very large outputs to prevent token limit issues:
Copy
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
Log all commands
Keep an audit trail of executed commands:
Copy
import logging
def log_command(command, output, user_id):
logging.info(f"User {user_id} executed: {command}")
logging.info(f"Output: {output[:200]}...") # Log first 200 chars
Sanitize outputs
Remove sensitive information from command outputs:
Copy
def sanitize_output(output):
# Remove potential secrets or credentials
import re
# Example: Remove AWS credentials
output = re.sub(r'aws_access_key_id\s*=\s*\S+', 'aws_access_key_id=***', output)
output = re.sub(r'aws_secret_access_key\s*=\s*\S+', 'aws_secret_access_key=***', output)
return output
The bash tool provides direct system access. Implement these essential safety measures:
Key recommendations
ulimit to set resource constraintssudo, rm -rf, etc.)The bash tool adds 245 input tokens to your API calls. Additional tokens are consumed by:
See tool use pricing for complete pricing details.
Development workflows
pytest && coverage reportnpm install && npm run buildgit status && git add . && git commit -m "message"File operations
wc -l *.csv && ls -lh *.csvfind . -name "*.py" | xargs grep "pattern"tar -czf backup.tar.gz ./dataSystem tasks
df -h && free -mps aux | grep pythonexport PATH=$PATH:/new/path && echo $PATHvim, less, or password promptsThe bash tool is most powerful when combined with the text editor and other tools.
Tool use overview
-----------------
Learn about tool use with Claude
Text editor tool
----------------
View and edit text files with Claude
Was this page helpful?
YesNo
Fine-grained tool streaming Code execution tool
Assistant
Responses are generated using AI and may contain mistakes.