콘텐츠로 이동

Bash 도구 (Bash Tool)

Bash 도구는 Claude가 셸 명령을 요청하면, 여러분의 애플리케이션이 지속적인(영구적인) bash 세션에서 그 명령을 실행하고 그 결과를 도구 결과(tool result)로 돌려주는 방식입니다.

참고: 이 기능에 zero data retention(ZDR)이 어떻게 적용되는지 보려면 API 및 데이터 보존 문서를 확인하세요.

빠른 시작 (Quick start)

Claude에게 도구 목록에 bash_20250124 타입의 bash 도구를 넘기면, Claude가 "현재 디렉터리의 모든 파이썬 파일을 나열해 줘" 같은 명령을 셸 명령으로 바꿔 요청할 수 있습니다.

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-5",
    "max_tokens": 1024,
    "tools": [
      {
        "type": "bash_20250124",
        "name": "bash"
      }
    ],
    "messages": [
      {
        "role": "user",
        "content": "List all Python files in the current directory."
      }
    ]
  }'

CLI

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

Python

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)

응답 (Output)

{
  "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",
      ...
    }
  ]
}

동작 방식 (How it works)

이 API는 무상태(stateless) 입니다. 셸 세션에 대한 어떤 상태도 요청 사이를 오가지 않습니다. 그래서 세션이 언제 시작되고, 얼마나 오래 유지되며, 언제 재시작되는지는 여러분의 애플리케이션이 결정합니다. 요청과 응답의 전체 흐름은 도구 호출 처리하기 (Handle tool calls) 문서를 참고하세요.

Bash 도구 구현하기 (Implement the bash tool)

도구 응답에서 bash라는 이름의 tool_use 블록을 찾아 실행하면 됩니다. 입력에 restart가 있으면 세션을 재시작하고, 아니면 command를 실행합니다. 각 tool_use 블록마다 tool_result를 하나씩 만들어 다음 사용자 메시지에 함께 돌려보냅니다.

Python

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)

        # One tool_result per tool_use block, all returned in the next user message
        tool_results.append({type: "tool_result", tool_use_id: content.id, content: result})

TypeScript

// One tool_result per tool_use block, all returned in the next user message
toolResults.push({ type: "tool_result", tool_use_id: block.id, content: result });

C#

var toolResults = new List<ToolResultBlockParam>();
foreach (var block in response.Content)
{
  ...
}

Ruby

# One tool_result per tool_use block, all returned in the next user message
tool_results << {type: "tool_result", tool_use_id: block.id, content: result}

stop_reasontool_use인 동안 실행하고 결과를 돌려주는 과정을 반복하면 됩니다. 전체 루프는 클라이언트 도구 결과 처리하기 (Handling results from client tools) 문서를 참고하세요.

예시: 전체 요청·응답 흐름

다음은 cURL, CLI, Python, TypeScript, Go, PHP, Ruby에서 "현재 디렉터리의 파이썬 파일 나열" 요청이 도구 호출로 이어지고, 그 결과가 다시 전달되는 전 과정을 보여줍니다.

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-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"
          }
        ]
      }
    ]
  }'

CLI

ant messages create <<'YAML'
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
          process_data.py
YAML

Python

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)

TypeScript

const client = new Anthropic();

const response = await 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"
        }
      ]
    }
  ]
});

console.log(response.content);

Go

client := anthropic.NewClient()
...

PHP

client = new Anthropic\Client();

$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_r($response->content);

Ruby

client = Anthropic::Client.new

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"
        }
      ]
    }
  ]
)

puts response.content

안전 확인 (Safety check)

이 페이지의 예시에서 보듯 &&(공백이 있는 명령 연결), 파이프, 리다이렉션 등이 실제로는 사용된다는 점을 감안하면, 이 확인 로직은 명백한 실수를 걸러내는 여행용 트립와이어(tripwire) 이지, 강제적인 경계는 아닙니다. cat data.txt|grep x처럼 연산자가 단어에 붙어 있는 경우는 토크나이저가 data.txt|grep을 한 토큰으로 유지하기 때문에 걸러내지 못합니다.

오류 처리 (Handle errors)

명령이 실패하면 tool_result 블록에 is_error: true를 붙여 돌려주면, Claude가 그 오류를 보고 다음 행동을 정할 수 있습니다.

명령이 30초 안에 끝나지 않을 때 (Timeout)

{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
      "content": "Error: command did not finish within 30 seconds",
      "is_error": true
    }
  ]
}

명령을 찾을 수 없을 때 (Command not found)

명령이 존재하지 않으면:

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

권한 문제일 때 (Permission denied)

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

가격 (Pricing)

모델 추가 입력 토큰 (Additional input tokens)
Claude Opus 5, Claude Opus 4.8, Claude Opus 4.7 325 tokens
Claude Opus 4.6, Claude Sonnet 4.6 및 이전 버전 244 tokens

추가 토큰은 다음 항목들이 소비합니다.

  • 명령 출력 (stdout/stderr)
  • 오류 메시지
  • 큰 파일 내용

전체 가격 정책은 도구 사용 가격 (tool use pricing) 문서를 참고하세요.