Инструмент bash
Позвольте Claude запрашивать команды оболочки, которые ваше приложение выполняет в постоянном сеансе bash и возвращает в виде результатов инструментов.
Инструмент bash — это клиентский инструмент: Claude не выполняет команды самостоятельно. Когда вы включаете инструмент в запрос, Claude отвечает блоком tool_use, в котором указана команда для выполнения. Ваше приложение выполняет эту команду в принадлежащем ему сеансе bash и возвращает вывод в блоке tool_result.
Ваше приложение поддерживает один процесс bash активным между вызовами инструмента, поэтому состояние сохраняется между командами. Рабочий каталог, переменные окружения и любые файлы, созданные командой, остаются доступными для следующей команды.
Текущая версия инструмента — bash_20250124. Сведения о поддержке моделей, бета-заголовках и более ранней версии см. в разделе Версии инструмента. Все инструменты, предоставляемые Anthropic, см. в Справочнике по инструментам.
Сценарии использования
- Рабочие процессы разработки: запуск команд сборки, тестов и инструментов разработки
- Автоматизация системы: выполнение скриптов, управление файлами, автоматизация задач
- Обработка данных: обработка файлов, запуск скриптов анализа, управление наборами данных
- Настройка окружения: установка пакетов, конфигурирование окружений
Быстрый старт
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 отвечает с stop_reason: "tool_use" и блоком tool_use, содержащим команду, которую должно выполнить ваше приложение:
{
"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"
}
}
]
}Выполните input.command в вашем сеансе bash и отправьте вывод обратно в виде tool_result. Полный цикл обмена см. в разделе Реализация инструмента bash.
Как это работает
Каждый вызов инструмента — это один цикл обмена между Claude и вашим приложением:
- Claude возвращает блок
tool_use, содержащийcommandдля выполнения. - Ваше приложение выполняет команду в своём сеансе bash.
- Ваше приложение возвращает вывод команды, stdout и stderr вместе, в Claude в блоке
tool_result. - Claude либо запрашивает другую команду в том же сеансе, либо отвечает текстом.
Claude также может вернуть несколько блоков tool_use в одном ответе. Выполните их по порядку в том же сеансе и верните все результаты в одном сообщении user. См. Параллельное использование инструментов.
API не хранит состояние. Никакие сведения о вашем сеансе оболочки не передаются между запросами, поэтому ваше приложение решает, когда сеанс начинается, как долго он живёт и когда его перезапускать. Полный цикл запроса и ответа см. в разделе Обработка вызовов инструментов.
Параметры
Определение инструмента bash имеет два обязательных поля, type и name, причём name должно быть bash. Инструмент не имеет схемы: вы не предоставляете input_schema, поскольку схема встроена в модель Claude и не может быть изменена. В следующей таблице перечислены входные поля, которые Claude задаёт при вызове инструмента.
| Параметр | Обязательный | Описание |
|---|---|---|
command | Да* | Команда bash для выполнения |
restart | Нет | Установите в true, чтобы перезапустить сеанс bash |
*Обязателен, если не используется restart
Чтобы обработать restart: true, завершите процесс оболочки, запустите новый и верните tool_result, подтверждающий перезапуск. Перезапущенный сеанс начинается с чистого состояния: рабочий каталог, переменные окружения и любые запущенные процессы исчезают.
Выполнить команду:
{
"command": "ls -la *.py"
}Перезапустить сеанс:
{
"restart": true
}Версии инструмента
bash_20250124 — текущая версия инструмента, и она не требует бета-заголовка. Её принимает каждая модель, начиная с Claude Sonnet 3.7 (выведена из эксплуатации), включая все текущие модели Claude.
Исходная версия bash_20241022 работает только с моделью Claude Sonnet 3.5 от октября 2024 года (выведена из эксплуатации). Запросы, использующие её, требуют заголовка anthropic-beta: computer-use-2024-10-22, а SDK предоставляют её только в своих бета-пространствах имён. В новых интеграциях следует использовать bash_20250124.
Пример: многошаговая автоматизация
Claude может связывать команды в цепочку между вызовами инструмента для выполнения многошаговой задачи:
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"}Сеанс сохраняет состояние между командами, поэтому файлы, созданные на шаге 2, доступны на шаге 3.
Реализация инструмента bash
Claude определяет, какую команду выполнить. Всё остальное принадлежит вашему приложению: процесс оболочки, тайм-аут и проверки безопасности. Следующие шаги показывают минимальную реализацию.
Создайте постоянный сеанс bash
Запустите один долгоживущий процесс bash и выполняйте каждую команду внутри него. Поскольку канал к работающему процессу никогда не сообщает о конце файла, сеанс выводит уникальную строку-маркер после каждой команды, чтобы отметить, где заканчивается вывод этой команды:
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 stateСеанс чередует stderr с stdout, поэтому сообщения об ошибках оказываются там, где они произошли. В примере опущено то, что также необходимо полной реализации: тайм-аут, который завершает оболочку и все запущенные ею процессы, когда команда зависает, а затем перезапускает сеанс. Рекомендация Используйте тайм-ауты команд показывает один из способов его добавить.
Обработайте вызовы инструментов от Claude
Извлеките и выполните команды из ответов 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) # Один tool_result на каждый блок tool_use, все возвращаются в следующем сообщении пользователя tool_results.append( {"type": "tool_result", "tool_use_id": content.id, "content": result} )Верните результат в Claude
Отправьте
tool_resultобратно в сообщенииuser, продолжающем тот же разговор. Claude либо запрашивает другую команду в том же сеансе, либо завершает свой ответ: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)Повторяйте цикл «выполнить и вернуть», пока
stop_reasonравенtool_use. Полный цикл см. в разделе Обработка результатов клиентских инструментов.Реализуйте меры безопасности
Добавьте проверку и ограничения. Используйте список разрешённых, а не список запрещённых: список запрещённых пропускает любую команду, которую он не предусмотрел. Пример также отклоняет операторы оболочки, которые встречаются как отдельные слова:
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" # Отклонять операторы оболочки, записанные отдельными словами 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Эта проверка — сигнальная ловушка для очевидных ошибок, а не граница принудительного контроля. Она отклоняет разделённые пробелами цепочки (
&&), конвейеры и перенаправление, которые используются в других примерах на этой странице. Она не обнаруживает оператор, приклеенный к слову, напримерcat data.txt|grep x, поскольку токенизатор сохраняетdata.txt|grepвнутри одного токена. Решите, какие команды и операторы разрешает ваше приложение. Настоящий контроль — это изоляция: запускайте весь сеанс внутри контейнера или виртуальной машины (см. Безопасность).
Обработка ошибок
Когда команда завершается неудачей или сеанс ломается, сообщите Claude, что произошло. Верните сообщение как содержимое tool_result и установите is_error в true, что помечает вызов инструмента как неудачный. См. Обработка ошибок с помощью is_error.
Если выполнение команды занимает слишком много времени:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "Error: command did not finish within 30 seconds",
"is_error": true
}
]
}Если команда не существует:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "bash: nonexistentcommand: command not found",
"is_error": true
}
]
}Если есть проблемы с правами доступа:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "bash: /root/sensitive-file: Permission denied",
"is_error": true
}
]
}Следуйте лучшим практикам реализации
Команда, которая никогда не завершается, например ожидающая ввода, блокирует сеанс навсегда, потому что её строка-маркер никогда не приходит. Задайте каждой команде крайний срок. Когда срок истекает, остановите оболочку и всё, что запустила команда, а затем перезапустите сеанс:
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:
# Группа — это оболочка и все процессы, запущенные командой
os.killpg(session.process.pid, signal.SIGKILL)
session.restart()
return f"Error: command did not finish within {timeout} seconds"Принудительное завершение останавливает зависшую команду и всё, что она запустила. Верните сообщение как tool_result с ошибкой (см. Обработка ошибок), что помечает вызов инструмента как неудачный.
Сохраняйте сеанс bash постоянным, чтобы поддерживать переменные окружения и рабочий каталог:
# Команды, выполняемые в одном сеансе, сохраняют состояние
commands = [
"cd /tmp",
"echo 'Hello' > test.txt",
"cat test.txt", # The session is still in /tmp
]Обрезайте большие выводы, чтобы избежать проблем с лимитом токенов:
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Ведите журнал аудита. Направляйте каждую команду через одну обёртку, которая записывает команду перед её выполнением и вывод после её завершения. Команда, которая зависает или ломает сеанс, всё равно оставляет запись:
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 outputПо умолчанию записи направляются в stderr; направьте их в файл или ваш конвейер журналирования, чтобы сохранить их. Включите всё, что связывает запись с запросом в вашем приложении, например конечного пользователя и tool_use_id.
Безопасность
Помимо изоляции, добавьте следующие меры контроля:
- Проверяйте команды перед их выполнением, используя список разрешённых, а не список запрещённых. См. Реализация инструмента bash.
- Установите ограничения ресурсов для процесса оболочки (ЦП, память и диск), например с помощью
ulimit. - Журналируйте каждую команду и её вывод, чтобы можно было провести аудит того, что выполнялось.
- Удаляйте учётные данные и другие секреты из вывода перед его возвратом в Claude.
Цены
Определение инструмента bash добавляет следующие входные токены к вашему запросу. Это в дополнение к системной подсказке использования инструментов для каждой модели, которая применяется всякий раз, когда присутствует какой-либо инструмент.
| Модель | Дополнительные входные токены |
|---|---|
| Claude Opus 5, Claude Opus 4.8 и Claude Opus 4.7 | 325 токенов |
| Claude Opus 4.6, Claude Sonnet 4.6 и более ранние | 244 токена |
Дополнительные токены расходуются на:
- Вывод команд (stdout/stderr)
- Сообщения об ошибках
- Содержимое больших файлов
Полные сведения о ценах см. в разделе цены на использование инструментов.
Распространённые шаблоны
Рабочие процессы разработки
- Запуск тестов:
pytest && coverage report - Сборка проектов:
npm install && npm run build - Операции Git:
git status && git add . && git commit -m "message"
Рекомендации по использованию git в качестве механизма контрольных точек и восстановления в длительных агентных рабочих процессах см. в разделе лучшие практики управления состоянием.
Операции с файлами
- Обработка данных:
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, запросы пароля или любую команду, ожидающую ввода на stdin. - Нет приложений с графическим интерфейсом: сеанс работает только в командной строке.
- Область действия сеанса: состояние сеанса bash находится на стороне клиента. Ваше приложение отвечает за поддержание сеанса оболочки между ходами.
- Ограничения вывода: API не обрезает результаты инструментов (запрос слишком большого размера отклоняется). Обрезайте большие выводы в вашем приложении перед их возвратом в Claude.
- Нет потоковой передачи: «streaming» (потоковая передача) не поддерживается — вывод достигает Claude только тогда, когда ваше приложение возвращает
tool_resultв следующем запросе.
Сочетание с другими инструментами
Инструмент bash хорошо сочетается с инструментом текстового редактора: Claude редактирует файл одним инструментом и запрашивает команду, которая его запускает, другим.
Следующие шаги
Просматривайте и изменяйте текстовые файлы для отладки, исправления и улучшения кода.
Подключите Claude к внешним инструментам и API. Узнайте, где выполняются инструменты, когда Claude их вызывает и какой инструмент подходит для вашей задачи.
Was this page helpful?