# Bash tool

---

<Note>
此功能符合[零数据留存 (ZDR)](/docs/en/build-with-claude/api-and-data-retention) 条件。当你的组织有 ZDR 安排时，通过此功能发送的数据在 API 响应返回后不会被存储。
</Note>

Bash tool 使 Claude 能够在持久的 bash 会话中执行 shell 命令，实现系统操作、脚本执行和命令行自动化。Shell 访问是 agent 的基础能力。在 [Terminal-Bench 2.0](https://github.com/terminal-bench/terminal-bench)（一个使用纯 shell 验证评估真实终端任务的基准测试）上，Claude 在获得持久 bash 会话访问后表现出显著的性能提升。

## 概述

Bash tool 为 Claude 提供：
- 维持状态的持久 bash 会话
- 运行任何 shell 命令的能力
- 访问环境变量和工作目录
- 命令链和脚本能力

模型支持参见[工具参考](/docs/en/agents-and-tools/tool-use/tool-reference)。

## 使用场景

- **开发工作流：** 运行构建命令、测试和开发工具
- **系统自动化：** 执行脚本、管理文件、自动化任务
- **数据处理：** 处理文件、运行分析脚本、管理数据集
- **环境设置：** 安装包、配置环境

## 快速开始

<CodeGroup>
```bash cURL
curl https://api.anthropic.com/v1/messages \
  -H "content-type: application/json" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-opus-4-7",
    "max_tokens": 1024,
    "tools": [
      {
        "type": "bash_20250124",
        "name": "bash"
      }
    ],
    "messages": [
      {
        "role": "user",
        "content": "List all Python files in the current directory."
      }
    ]
  }'
```

```bash CLI
ant messages create \
  --model claude-opus-4-7 \
  --max-tokens 1024 \
  --tool '{type: bash_20250124, name: bash}' \
  --message '{role: user, content: List all Python files in the current directory.}'
```

```python Python
import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=1024,
    tools=[{"type": "bash_20250124", "name": "bash"}],
    messages=[
        {"role": "user", "content": "List all Python files in the current directory."}
    ],
)

print(response)
```

```typescript TypeScript
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const response = await client.messages.create({
  model: "claude-opus-4-7",
  max_tokens: 1024,
  tools: [{ type: "bash_20250124", name: "bash" }],
  messages: [
    {
      role: "user",
      content: "List all Python files in the current directory."
    }
  ]
});

console.log(response);
```

```csharp C#
using Anthropic;
using Anthropic.Models.Messages;

var client = new AnthropicClient();

var response = await client.Messages.Create(
    new()
    {
        Model = Model.ClaudeOpus4_7,
        MaxTokens = 1024,
        Tools = [new ToolBash20250124()],
        Messages =
        [
            new()
            {
                Role = Role.User,
                Content = "List all Python files in the current directory.",
            },
        ],
    }
);

Console.WriteLine(response);
```

```go Go hidelines={1..10,-1}
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/anthropics/anthropic-sdk-go"
)

func main() {
	client := anthropic.NewClient()

	response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
		Model:     anthropic.ModelClaudeOpus4_7,
		MaxTokens: 1024,
		Tools: []anthropic.ToolUnionParam{
			{OfBashTool20250124: &anthropic.ToolBash20250124Param{}},
		},
		Messages: []anthropic.MessageParam{
			anthropic.NewUserMessage(anthropic.NewTextBlock("List all Python files in the current directory.")),
		},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(response)
}
```

```java Java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;
import com.anthropic.models.messages.ToolBash20250124;

void main() {
    AnthropicClient client = AnthropicOkHttpClient.fromEnv();

    Message response = client.messages().create(
        MessageCreateParams.builder()
            .model(Model.CLAUDE_OPUS_4_7)
            .maxTokens(1024)
            .addTool(ToolBash20250124.builder().build())
            .addUserMessage("List all Python files in the current directory.")
            .build()
    );

    IO.println(response);
}
```

```php PHP hidelines={1}
<?php

use Anthropic\Client;
use Anthropic\Messages\ToolBash20250124;

$client = new Client();

$response = $client->messages->create(
    model: 'claude-opus-4-7',
    maxTokens: 1024,
    tools: [new ToolBash20250124()],
    messages: [
        ['role' => 'user', 'content' => 'List all Python files in the current directory.'],
    ],
);

echo $response;
```

```ruby Ruby
require "anthropic"

client = Anthropic::Client.new

response = client.messages.create(
  model: "claude-opus-4-7",
  max_tokens: 1024,
  tools: [{type: "bash_20250124", name: "bash"}],
  messages: [
    {role: "user", content: "List all Python files in the current directory."}
  ]
)

puts response
```
</CodeGroup>

## 工作原理

Bash tool 维护一个持久会话：

1. Claude 确定要运行的命令
2. 你在 bash shell 中执行命令
3. 将输出（stdout 和 stderr）返回给 Claude
4. 会话状态在命令之间持久化（环境变量、工作目录）

## 参数

| 参数 | 必填 | 描述 |
|-----------|----------|-------------|
| `command` | 是* | 要运行的 bash 命令 |
| `restart` | 否 | 设置为 `true` 以重启 bash 会话 |

*除非使用 `restart`，否则必填

<section title="使用示例">

运行命令：

```json
{
  "command": "ls -la *.py"
}
```

重启会话：

```json
{
  "restart": true
}
```

</section>

## 示例：多步骤自动化

Claude 可以链接命令来完成复杂任务：

```text
用户请求：
"Install the requests library and create a simple Python script that
fetches a joke from an API, then run it."

Claude 的工具调用：
1. 安装包
   {"command": "pip install requests"}

2. 创建脚本
   {"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. 运行脚本
   {"command": "python fetch_joke.py"}
```

会话在命令之间维护状态，因此步骤 2 中创建的文件在步骤 3 中可用。

## 实现 bash tool

Bash tool 作为无 schema 工具实现。使用此工具时，你不需要像其他工具那样提供输入 schema；schema 内置在 Claude 的模型中，无法修改。

<Steps>
  <Step title="设置 bash 环境">
    创建一个 Claude 可以交互的持久 bash 会话：
    ```python hidelines={-2..-1}
    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()

        def _start_readers(self): ...
    ```
  </Step>
  <Step title="处理命令执行">
    创建一个执行命令并捕获输出的函数：
    ```python hidelines={1..2,-1}
    class BashSession:
        def _read_output(self, timeout): ...
        def execute_command(self, command):
            # 将命令发送到 bash
            self.process.stdin.write(command + "\n")
            self.process.stdin.flush()

            # 捕获带超时的输出
            output = self._read_output(timeout=10)
            return output

        process = None
    ```
  </Step>
  <Step title="处理 Claude 的工具调用">
    从 Claude 的响应中提取并执行命令：
    ```python hidelines={1..6}
    from types import SimpleNamespace as _SN

    response = _SN(
        content=[_SN(type="tool_use", name="bash", input={"command": "ls"}, id="toolu_01")]
    )
    bash_session = _SN(restart=lambda: None, execute_command=lambda c: "output")
    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)

            # 将结果返回给 Claude
            tool_result = {
                "type": "tool_result",
                "tool_use_id": content.id,
                "content": result,
            }
    ```
  </Step>
  <Step title="实现安全措施">
    添加验证和限制。使用允许列表而非阻止列表，因为阻止列表很容易被绕过。拒绝 shell 操作符，使链接的命令无法绕过允许列表：
    ```python
    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
    ```
    此检查是第一道防线。要获得更强的隔离，请使用 `shell=False` 运行已验证的命令，并将 `shlex.split(command)` 作为参数列表传递，这样 shell 就不会解释字符串。
  </Step>
</Steps>

### 错误处理

实现 bash tool 时，处理各种错误场景：

<section title="命令执行超时">

如果命令执行时间过长：

```json
{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
      "content": "Error: Command timed out after 30 seconds",
      "is_error": true
    }
  ]
}
```

</section>

<section title="命令未找到">

如果命令不存在：

```json
{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
      "content": "bash: nonexistentcommand: command not found",
      "is_error": true
    }
  ]
}
```

</section>

<section title="权限被拒绝">

如果有权限问题：

```json
{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
      "content": "bash: /root/sensitive-file: Permission denied",
      "is_error": true
    }
  ]
}
```

</section>

### 遵循实现最佳实践

<section title="使用命令超时">

实现超时以防止命令挂起：
```python hidelines={1..3}
import subprocess


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"
```

</section>

<section title="维护会话状态">

保持 bash 会话持久化以维护环境变量和工作目录：
```python
# 在同一会话中运行的命令会维护状态
commands = [
    "cd /tmp",
    "echo 'Hello' > test.txt",
    "cat test.txt",  # 这可以工作，因为我们仍在 /tmp 中
]
```

</section>

<section title="处理大型输出">

截断非常大的输出以防止 token 限制问题：
```python
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
```

</section>

<section title="记录所有命令">

保留已执行命令的审计跟踪：
```python
import logging


def log_command(command, output, user_id):
    logging.info(f"User {user_id} executed: {command}")
    logging.info(f"Output: {output[:200]}...")  # 记录前 200 个字符
```

</section>

<section title="清理输出">

从命令输出中移除敏感信息：
```python
def sanitize_output(output):
    # 移除潜在的密钥或凭证
    import re

    # 示例：移除 AWS 凭证
    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
```

</section>

## 安全

<Warning>
Bash tool 提供直接的系统访问。请实施以下基本安全措施：
- 在隔离环境中运行（Docker/VM）
- 实施命令过滤和允许列表
- 设置资源限制（CPU、内存、磁盘）
- 记录所有已执行的命令
</Warning>

### 关键建议
- 使用 `ulimit` 设置资源约束
- 过滤危险命令（`sudo`、`rm -rf` 等）
- 以最小用户权限运行
- 监控和记录所有命令执行

## 定价

Bash tool 为你的 API 调用增加 **245 个输入 token**。

以下内容会消耗额外 token：
- 命令输出（stdout/stderr）
- 错误消息
- 大型文件内容

完整的定价详情参见[工具使用定价](/docs/en/agents-and-tools/tool-use/overview#pricing)。

## 常见模式

### 开发工作流
- 运行测试：`pytest && coverage report`
- 构建项目：`npm install && npm run build`
- Git 操作：`git status && git add . && git commit -m "message"`

#### 基于 Git 的检查点

Git 在长时间运行的 agent 工作流中作为结构化的恢复机制，而不仅仅是保存更改的方式：

- **捕获基线：** 在任何 agent 工作开始之前，提交当前状态。这是已知良好的起点。
- **按功能提交：** 每个完成的功能都有自己的提交。如果后续出现问题，这些提交可以作为回滚点。
- **在会话开始时重建状态：** 读取 `git log` 和进度文件以了解已完成的工作和接下来的内容。
- **失败时回滚：** 如果工作出错，`git checkout` 会回退到最后一个良好的提交，而不是尝试调试损坏的状态。

### 文件操作
- 处理数据：`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` 或密码提示
- **无 GUI 应用：** 仅限命令行
- **会话范围：** Bash 会话状态在客户端。API 是无状态的。你的应用程序负责在轮次之间维护 shell 会话。
- **输出限制：** 大型输出可能被截断
- **无流式传输：** 结果在完成后返回

## 与其他工具组合

Bash tool 与[文本编辑器](/docs/en/agents-and-tools/tool-use/text-editor-tool)和其他工具组合使用时最强大。

<Note>
如果你同时使用 [code execution tool](/docs/en/agents-and-tools/tool-use/code-execution-tool)，Claude 可以访问两个独立的执行环境：你的本地 bash 会话和 Anthropic 的沙箱容器。状态不会在它们之间共享。有关提示 Claude 区分环境的指导，请参见[将代码执行与其他执行工具一起使用](/docs/en/agents-and-tools/tool-use/code-execution-tool#using-code-execution-with-other-execution-tools)。
</Note>

## 下一步

<CardGroup cols={2}>
  <Card
    title="工具使用概览"
    icon="tool"
    href="/docs/en/agents-and-tools/tool-use/overview"
  >
    了解 Claude 的工具使用
  </Card>

  <Card
    title="文本编辑器工具"
    icon="file"
    href="/docs/en/agents-and-tools/tool-use/text-editor-tool"
  >
    使用 Claude 查看和编辑文本文件
  </Card>
</CardGroup>
