Skip to content

cli/cmd_batch.py — batch 命令 ​

CLItyper批量

📦 apkid-ai-cli batch 批量扫描目录下的多个文件,用 rich Progress 显示进度条(走 stderr),结果聚合成单个 JSON 数组输出到 stdout。

📋 文件内容一览 ​

符号类型说明
batch(...)functyper 命令回调,批量扫描目录

模块仅导出 batch 函数,由 app.py 注册为 batch 命令。

🖥️ 命令签名 ​

bash
apkid-ai-cli batch <directory> [options]

📑 参数表 ​

参数类型默认说明
directoryPath(必填)含待扫描文件的目录,exists=True
--recursive, -rboolFalse递归扫描子目录
--pattern, -pstr*.apk文件 glob 模式
--output, -oOptional[Path]None写入文件而非 stdout
--format, -fOutputFormatjson输出格式
--timeout, -tint30YARA 扫描超时(秒)
--typingTypingMethodmagic文件识别方式
--scan-depthint2嵌套 ZIP 归档最大递归深度
--entry-max-scan-sizeint0单个 ZIP 条目最大扫描字节数(0=不限)
--include-typesboolFalse结果含 file_type 检测
--verbose, -vboolFalse调试日志

🔧 源码要点 ​

文件收集 ​

python
if recursive:
    files = sorted(target_path.rglob(pattern))
else:
    files = sorted(target_path.glob(pattern))

rglob/glob 二选一,结果 sorted 保证输出顺序稳定。

空文件集合 ​

python
if not files:
    result = json.dumps(
        {
            "error": False,
            "scanned": 0,
            "results": [],
            "message": f"No files matching '{pattern}' found in {directory}",
        },
        ensure_ascii=False,
    )
    output_result(result, output)
    return

注意:空集合不是错误(error: False),带 message 提示原因。这是与异常路径(error_exit)的关键区别。

进度条(stderr) ​

python
from apkid.cli.app import console as _console

with Progress(
    SpinnerColumn(),
    TextColumn("[progress.description]{task.description}"),
    console=_console,
) as progress:
    task = progress.add_task(f"Scanning {len(files)} files...", total=len(files))
    for f in files:
        results = scanner.scan_file(str(f))
        formatted = formatter.format_dict(results, str(f), include_types=include_types)
        all_results.append(formatted)
        progress.advance(task)

要点:

  • 复用 app.py 的 console:该 Console 是 Console(stderr=True),进度条走 stderr,不污染 stdout 的 JSON 结果。这是 AI 可解析输出的关键。
  • 用 format_dict 而非 format:每个文件产出 dict(非字符串),便于后续聚合进 results 数组。format 会产出带 schema_version 的完整字符串,不适合聚合。
  • 逐文件 scan_file:复用同一个 scanner 实例,YARA 规则只加载一次。

聚合输出 ​

python
batch_output = json.dumps(
    {
        "error": False,
        "scanned": len(all_results),
        "results": all_results,
    },
    ensure_ascii=False,
    indent=2,
)
output_result(batch_output, output)

scanned 即结果数组长度,便于 AI 快速核对数量。

🔗 调用链 ​

batch() → common.make_scanner() → AIOutputFormatter
        → Path.rglob/glob 收集文件
        → (空集合) → output_result({error:false,scanned:0,...}) 直出
        → (非空)   → Progress(stderr) 循环 scanner.scan_file + format_dict
                   → 聚合 → output_result({error:false,scanned:N,results:[...]})
异常 → common.error_exit()

🤝 与其它模块的关系 ​

  • 依赖 common.py:make_scanner、output_result、error_exit、枚举。
  • 依赖 app.py:from apkid.cli.app import console as _console,复用 stderr Console 跑进度条。
  • 依赖 ai_output.py:AIOutputFormatter.format_dict(注意是 dict 版)。
  • 与 cmd_scan.py 对比:scan 用 format 出字符串,batch 用 format_dict 出 dict 再聚合。
  • MCP 对应:mcp/tools_batch.py(若存在)走同样 make_scanner + format_dict 路径。

📍 相关 ​

基于 GPL & Commercial 双重许可发布