跳转至

Bash 工具

Bash 工具提供带有内置安全验证的 Shell 命令执行功能,专为需要以编程方式运行 Shell 命令的 AI Agent 工作流设计。

类概述

  • BashTool - 通过 subprocess.run 执行 Shell 命令,内置拒绝列表在执行前阻止已知的危险模式。

使用方法

基本用法

from toolregistry_hub import BashTool

# 执行简单命令
result = BashTool.execute("echo hello world")
print(result["stdout"])   # "hello world\n"
print(result["exit_code"])  # 0

# 指定工作目录
result = BashTool.execute("ls -la", cwd="/tmp")

# 自定义超时时间(秒)
result = BashTool.execute("long_running_script.sh", timeout=300)

返回值

execute() 返回包含以下键的字典:

类型 描述
stdout str 捕获的标准输出(截断上限 64 KB)
stderr str 捕获的标准错误(截断上限 64 KB)
exit_code int 进程退出码,超时时为 -1
timed_out bool 进程是否因超时被终止

错误处理

# 非零退出码
result = BashTool.execute("ls /nonexistent")
if result["exit_code"] != 0:
    print(f"Error: {result['stderr']}")

# 超时
result = BashTool.execute("sleep 60", timeout=5)
if result["timed_out"]:
    print("命令超时")

# 危险命令(抛出 ValueError)
try:
    BashTool.execute("rm -rf /")
except ValueError as e:
    print(f"已阻止: {e}")

安全机制

内置拒绝列表

BashTool 包含硬编码的拒绝列表,阻止已知的危险命令模式。该拒绝列表不可禁用,作为安全底线。

命令按 Shell 操作符(&&||;)分段,每段独立检查。

类别 阻止的模式
破坏性文件操作 rm -rf /rm -rf ~rm -rf *mkfsdd if=> /dev/sd*
权限提升 sudosu -chmod -R 777 /chown -R
代码注入 evalexeccurl\|shwget\|sh
Fork 炸弹 :(){ :\|:& };:
Git 破坏性操作 git push --forcegit reset --hardgit clean -f
系统控制 shutdownreboothaltkill -9 1

设计依据

拒绝列表基于对 6 个 AI 编程 CLI 工具(Claude Code、Codex、Aider、Kilo Code、Cline/Roo Code、Pi)安全方案的调研,涵盖了业界最常见的阻止模式。

本工具不提供:

  • 操作系统级沙箱(请在部署层使用容器或虚拟机隔离)
  • 交互式审批提示(MCP 协议限制)
  • 基于 AST 的 Shell 解析(v1 使用正则匹配)

MCP 服务端点

通过 MCP 服务运行时,此工具暴露为:

POST /tools/bash/execute

参数:

参数 类型 必填 默认值 描述
command string - 要执行的 Shell 命令
timeout integer 120 超时秒数
cwd string null 工作目录

API 参考

toolregistry_hub.bash_tool.BashTool

Shell command execution with built-in safety validation.

execute staticmethod

execute(command: str, timeout: int = 120, cwd: str | None = None) -> dict

Execute a shell command and return its output.

The command is first validated against a built-in deny list of known-dangerous patterns. If the command passes validation it is executed via subprocess.run with shell=True.

Parameters:

Name Type Description Default
command str

The shell command to execute.

required
timeout int

Maximum wall-clock seconds before the process is killed. Defaults to 120.

120
cwd str | None

Working directory for the command. If None, the current process working directory is used.

None

Returns:

Type Description
dict

A dict with keys:

dict
  • stdout (str): captured standard output (truncated at 64 KB).
dict
  • stderr (str): captured standard error (truncated at 64 KB).
dict
  • exit_code (int): process exit code, or -1 on timeout.
dict
  • timed_out (bool): whether the process was killed due to timeout.

Raises:

Type Description
ValueError

If the command matches a dangerous pattern.

FileNotFoundError

If cwd is specified but does not exist.

Source code in toolregistry_hub/bash_tool.py
@staticmethod
def execute(
    command: str,
    timeout: int = 120,
    cwd: str | None = None,
) -> dict:
    """Execute a shell command and return its output.

    The command is first validated against a built-in deny list of
    known-dangerous patterns.  If the command passes validation it is
    executed via ``subprocess.run`` with ``shell=True``.

    Args:
        command: The shell command to execute.
        timeout: Maximum wall-clock seconds before the process is
            killed.  Defaults to 120.
        cwd: Working directory for the command.  If ``None``, the
            current process working directory is used.

    Returns:
        A dict with keys:

        - ``stdout`` (str): captured standard output (truncated at 64 KB).
        - ``stderr`` (str): captured standard error (truncated at 64 KB).
        - ``exit_code`` (int): process exit code, or ``-1`` on timeout.
        - ``timed_out`` (bool): whether the process was killed due to
          timeout.

    Raises:
        ValueError: If the command matches a dangerous pattern.
        FileNotFoundError: If *cwd* is specified but does not exist.
    """
    # Validate safety
    _validate_command(command)

    # Validate cwd
    if cwd is not None:
        cwd_path = Path(cwd)
        if not cwd_path.is_dir():
            raise FileNotFoundError(f"Working directory does not exist: {cwd}")

    try:
        result = subprocess.run(
            command,
            shell=True,
            capture_output=True,
            text=True,
            timeout=timeout,
            cwd=cwd,
        )
        return {
            "stdout": _truncate(result.stdout),
            "stderr": _truncate(result.stderr),
            "exit_code": result.returncode,
            "timed_out": False,
        }
    except subprocess.TimeoutExpired as exc:
        stdout = exc.stdout
        stderr = exc.stderr
        return {
            "stdout": _truncate(stdout if isinstance(stdout, str) else ""),
            "stderr": _truncate(stderr if isinstance(stderr, str) else ""),
            "exit_code": -1,
            "timed_out": True,
        }