<!-- title: p模式结构化输出跑批量审查 -->

## 概述

本教程聚焦 Claude Code 的无头自动化能力：用 `-p`（print 模式）把 Claude 变成可被脚本调用的"无界面引擎"，用 `--output-format json --json-schema` 让它吐出机器可读的结构化结果，再配一个调度脚本实现跨多文件的**批量代码审查**，最后用 hooks 给流水线加上确定性的质量门禁与成本核算。学完你能搭出一条"喂一批文件 → 并行审查 → 结构化聚合 → 一份报告"的命令行流水线。适合已经能用交互式 Claude Code、想把重复任务自动化的开发者与工程效能同学。

## 前置条件

- 已安装 Claude Code（`claude --version` 能输出版本号，建议 v2.1.128 以上以获得 `--json-schema` 与 10MB stdin 限制等特性）
- 终端里装好 `jq`（`jq --version`），用于解析 JSON 输出
- 懂基本 Bash：管道、重定向、`xargs`、`for` 循环
- 一份待审查的代码仓库（本教程用任意 Python 项目即可）
- `ANTHROPIC_API_KEY` 已配置，或已通过 `claude` 登录

## 第一步：理解 -p 无头模式的三种输出

交互式 Claude Code 是给人看的；脚本化场景要的是"给一句 prompt、拿一个可解析的结果"。`-p`（或 `--print`）就是这把钥匙。它的三种 `--output-format` 决定了你怎么消费结果：

```bash
# text：纯文本，最省事，适合直接 > 到文件或拼接
claude -p "用一句话总结 auth.py 的作用" --output-format text

# json：单条 JSON，含 result / session_id / total_cost_usd / usage
claude -p "总结这个项目" --output-format json | jq -r '.result'

# stream-json：逐行 JSON 事件流，适合实时进度展示
claude -p "解释递归" --output-format stream-json --verbose
```

批量任务的核心是 **`json` 格式**：因为它把"答案"和"元数据"（session id、token 用量、`total_cost_usd` 花费）打包在一起，你既能取结果，又能事后核算成本，而不必去后台 Dashboard 查。

**预期结果**：运行 `--output-format json` 会返回一段形如 `{"type":"result","result":"...","session_id":"...","total_cost_usd":0.0123,"usage":{...}}` 的 JSON。

**常见问题**：
- *提示要权限确认，脚本卡住*：加 `--allowedTools "Read"` 等把要用的工具预批准掉，批量任务才不会中途停。
- *管道喂的内容太大被拒*：自 v2.1.128 起 stdin 上限 10MB，超过会非零退出。解法是把大文件写到磁盘，在 prompt 里引用路径而不是用管道。

## 第二步：用 --json-schema 锁定结构化输出

批量审查最怕"每次返回格式不一样"。`--json-schema` 让你给 Claude 一份 JSON Schema，它会强制把答案塞进这个结构，结果出现在 `structured_output` 字段里。这一步是把"会读代码的助手"变成"会填表的工人"的关键。

```bash
claude --bare -p "审查 src/auth.py 的安全问题" \
  --allowedTools "Read" \
  --output-format json \
  --json-schema '{
    "type":"object",
    "properties":{
      "severity":{"type":"string","enum":["high","medium","low"]},
      "findings":{
        "type":"array",
        "items":{
          "type":"object",
          "properties":{
            "file":{"type":"string"},
            "line":{"type":"integer"},
            "issue":{"type":"string"},
            "suggestion":{"type":"string"}
          },
          "required":["file","line","issue","suggestion"]
        }
      },
      "summary":{"type":"string"}
    },
    "required":["severity","findings","summary"]
  }' | jq '.structured_output'
```

注意开头的 `--bare`：它会跳过对 hooks、skills、plugins、MCP、CLAUDE.md 的自动发现，启动更快、行为更确定——同一台机器和不同机器跑出来的结果一致，这正是 CI 与脚本最想要的特性。`--bare` 也被官方定为未来 `-p` 的默认模式。

**预期结果**：`jq '.structured_output'` 输出符合 schema 的对象，`severity` 是枚举之一，`findings` 是数组，每条都有 file/line/issue/suggestion。

**常见问题**：
- *偶尔字段缺失*：Schema 里放进 `required` 的字段偶尔会被模型省略，可在解析脚本里对缺失字段填默认值（如 `"line":0`），别让 `jq` 报错中断整批。
- *想读多个文件*：`--allowedTools "Read"` 加上 prompt 里列出路径即可；不要把整个仓库 pipe 进来。

## 第三步：写批处理调度脚本（并行 + 聚合）

有了"单文件结构化审查"的能力，批量化就是把"文件列表"喂给"调度器"。下面这个脚本用 `xargs -P` 做并发，每个文件一个 `-p` 调用，结果用 `jq` 抽取后追加进一份汇总 JSONL，最后渲染成 Markdown 报告。

```bash
#!/usr/bin/env bash
# batch-review.sh —— 批量结构化代码审查
set -euo pipefail

GLOB="${1:-src/**/*.py}"          # 第一个参数：文件通配
CONCURRENCY="${2:-4}"             # 第二个参数：并发度
OUT="review-$(date +%Y%m%d-%H%M%S).jsonl"
REPORT="report.md"

SCHEMA='{"type":"object","properties":{"severity":{"type":"string","enum":["high","medium","low"]},"findings":{"type":"array","items":{"type":"object","properties":{"file":{"type":"string"},"line":{"type":"integer"},"issue":{"type":"string"},"suggestion":{"type":"string"}},"required":["file","line","issue","suggestion"]}},"summary":{"type":"string"}},"required":["severity","findings","summary"]}'

review_one() {
  local f="$1"
  # 每个 -p 调用都吐出完整 json：我们只保留 structured_output + 成本
  claude --bare -p "审查文件 $f 的安全与质量问题，只针对该文件。" \
    --allowedTools "Read" \
    --output-format json \
    --json-schema "$SCHEMA" \
    | jq -c --arg f "$f" '{
        file:$f,
        severity:.structured_output.severity,
        findings:.structured_output.findings,
        summary:.structured_output.summary,
        cost:.total_cost_usd
      }'
}
export -f review_one
export SCHEMA

# 1) 发现文件 + 并行审查 → 每行一条 JSON 写入 OUT
# shellcheck disable=SC2086
printf '%s\n' $GLOB | xargs -I{} -P"$CONCURRENCY" bash -c 'review_one "$@"' _ {} >> "$OUT"

# 2) 渲染报告：按 severity 排序、列出 findings、核算总成本
{
  echo "# 批量代码审查报告"
  echo
  echo "审查文件数：$(jq -s 'length' "$OUT")"
  echo "高危项数：$(jq -sr 'map(select(.severity=="high"))|length' "$OUT")"
  echo "总成本：\$$(jq -sr '[.[].cost]|add // 0' "$OUT")"
  echo
  echo "## 高危问题"
  jq -sr 'map(select(.severity=="high").findings[])|
          map("| \(.file):\(.line) | \(.issue) | \(.suggestion) |")|
          "---\n| 文件:行 | 问题 | 建议 |\n|---|---|---|\n" + (join("\n"))' "$OUT"
} > "$REPORT"

echo "完成：详见 $REPORT"
```

**预期结果**：跑完得到 `review-*.jsonl`（每行一个文件的结构化结果）和 `report.md`（含统计、成本、高危表格）。把并发度 `4` 调大可缩短墙钟时间，但要注意 API 速率限制。

**常见问题**：
- *`--bare` 下背景任务没跑完就被杀*：自 v2.1.182 起，`-p` 对后台子代理的等待上限默认 10 分钟（环境变量 `CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS` 控制，设 `0` 表示不限）。如果你的审查里 Claude 自己起了后台子代理，注意这个上限。
- *某个文件审查失败导致 `set -e` 全盘退出*：在 `review_one` 里把 `claude ...` 的退出码吞掉（如 `... || echo '{}'`），别让单点失败拖垮整批。

## 第四步：给流水线加 hooks（关键陷阱：bare 模式会跳过 hooks）

批量审查是**只读**的，用 `--bare` 没问题。但如果下一步你想让 Claude **批量自动修复**问题并落盘，就需要 Edit/Write 工具，这时候 hooks（如编辑后自动格式化）才派得上用场。这里有一个最容易踩的坑：

> **`--bare` 会跳过所有 hooks**，因为它根本不读配置。要让 hook 生效，要么不用 `--bare`，要么用 `--settings` 显式注入。

下面给自动修复场景配一个 `PostToolUse` 钩子：每次 Edit/Write 之后自动跑格式化。把它写进项目的 `.claude/settings.json`：

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs -r npx prettier --write"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          { "type": "command", "command": "echo \"[audit] $(date) 修复任务结束\" >> .claude/audit.log" }
        ]
      }
    ]
  }
}
```

然后批量自动修复时**故意不带 `--bare`**，并显式带上工具白名单：

```bash
claude -p "审查并直接修复 src/auth.py 里的高危安全问题，保存修改" \
  --allowedTools "Read,Edit,Bash" \
  --output-format json > fix-auth.json
```

这样每次 Edit 之后，`PostToolUse` 钩子都会确定性地跑一遍格式化——不依赖模型"记得"去格式化，而是**强制保证**。`Stop` 钩子则在每轮结束时写审计日志，方便你事后核对哪个文件被改过。

**预期结果**：文件被修改后会自动经过 prettier；`.claude/audit.log` 里按时间记录每次修复任务的结束。

**常见问题**：
- *配了 hook 却不触发*：多半是你同时用了 `--bare`。要么去掉 `--bare`，要么改用 `claude -p ... --settings ./.claude/settings.json` 把配置显式喂进去。
- *`/hooks` 里看不到*：交互式 `claude` 下输入 `/hooks` 是只读浏览器，能看到事件计数；若显示无配置，说明路径或 JSON 写错了，先在交互模式里验证再搬到脚本。

## 第五步：用 stream-json 做实时进度，用成本字段做核算

批量大时，干等到脚本结束才看到结果很焦虑。`stream-json` 能逐行吐事件，让你边跑边看进度；而每个 `json` 输出里的 `total_cost_usd` 让你能在报告里直接核算总花费。把审查脚本改造一下，加一个进度探针：

```bash
# 实时流式 + 只取最终 result 事件，同时累计成本
claude --bare -p "审查 src/payments.py" \
  --allowedTools "Read" \
  --output-format stream-json --verbose \
  | jq -rc --unbuffered 'select(.type=="assistant")'
```

整批跑完后，前面脚本里已经用 `jq -sr '[.[].cost]|add'` 算出了总成本。这就形成闭环：**每条结果带成本 → 聚合时求和 → 报告里直接显示花了多少钱**，无需登录后台。

## 实战案例：给一个 Python 服务批量体检

假设你有一个微服务仓库，`src/` 下有十几个模块，安全同学让你一次性把"硬编码密钥、SQL 拼接、未校验输入"扫一遍并出报告。

1. 在仓库根目录建好上面的 `batch-review.sh`。
2. 执行 `./batch-review.sh 'src/**/*.py' 6`，并发 6 跑起来。
3. 期间另开一个终端 `tail -f .claude/audit.log`（如果你启用了 Stop 钩子）或观察脚本滚动输出。
4. 跑完打开 `report.md`：顶部是统计（文件数、高危数、总成本），下面是按高危优先排序的问题表格，每行带 `文件:行` 可直接跳转。
5. 对高危项，挑出来跑第四步的自动修复流程（**不带 `--bare`** 以触发格式化钩子），用 `--resume` 或 `--continue` 在同一 session 里继续追问修复是否彻底。

这条流水线的妙处在于：**审查（只读、bare、快且确定）** 与 **修复（可写、带 hooks、强制质量门禁）** 用两种配置分开处理，既快又稳。

## 工作流程图

```mermaid
flowchart TD
    A["文件列表<br/>src/**/*.py"] --> B["batch-review.sh<br/>xargs -P 并发"]
    B --> C["每个文件一个<br/>claude --bare -p"]
    C -->|"--output-format json"| D["结构化输出<br/>structured_output"]
    C -->|"total_cost_usd"| E["成本字段"]
    D --> F["jq 聚合<br/>→ review.jsonl"]
    E --> F
    F --> G["渲染 report.md<br/>统计+高危表+总成本"]
    G --> H{需要自动修复?}
    H -->|是| I["claude -p 修复<br/>不带 --bare"]
    I --> J["PostToolUse 钩子<br/>自动格式化"]
    J --> K["Stop 钩子<br/>写审计日志"]
    H -->|否| L["交付报告"]
    K --> L
```

## 延伸阅读

- 把 `-p` 的批量能力结合 `--resume`/`--continue`，可以做出"可中断、可续跑"的批量任务，适合跑一晚上都没跑完的超大批次。
- 若要把批量任务按时间表无人值守执行（如每天凌晨扫一遍），可叠加 Claude Code 的"按计划运行 prompt"（`/loop` 与定时任务）能力。
- 对跨多仓库的大规模批量，可给每个仓库一个 git worktree 隔离，再在各自 worktree 里并行跑 `-p`，避免互相污染工作区。

## 训练营适用性评估

- **适用类型**：工程效能（DevEx）、代码质量、CI/CD 自动化、AI 辅助开发方向的训练营；中高级班。
- **基础要求**：学员需先掌握交互式 Claude Code 与基本 Bash/jq。
- **教学时长**：建议 2.5–3 小时（讲解 45 分钟 + 动手搭流水线 90 分钟 + 联调 hooks 与成本核算 30 分钟）。
- **可裁剪**：时间紧时可省略第五步的 stream-json 实时进度，聚焦"批量审查 + 报告"主干。

## 参考来源

1. [Run Claude Code programmatically — Claude Code Docs](https://docs.anthropic.com/en/docs/claude-code/headless) — 官方 `-p` / `--bare` / `--output-format` / `--json-schema` 与成本字段、stdin 上限、后台任务等待上限的权威说明。
2. [Hooks reference — Claude Code Docs](https://code.claude.com/docs/en/hooks) — Hook 事件全集、settings.json 配置 schema、matcher/if 过滤与退出码、`PostToolBatch` 等事件定义。
3. [Automate actions with hooks — Claude Code Docs](https://code.claude.com/docs/en/hooks-guide) — hooks 实战入门，含 PostToolUse 自动格式化、Stop 通知、matcher 与 `if` 字段的可用示例。
4. [Claude Code Headless Mode: Non-Interactive & CI Usage (2026)](https://claude-code-examples.vercel.app/claude-code-headless-mode/) — 第三方对 `-p` 在 CI/CD、脚本编排与管道集成场景的补充实践。
5. [Using Claude Code Programmatically — Gist](https://gist.github.com/JacobFV/2c4a75bc6a835d2c1f6c863cfcbdfa5a) — `--print --output-format` 在真实脚本中绕过 TUI、做结构化消费的工程经验。

# 汇总：高风险与 critical 项
jq -s '
  [.[] | .structured_output // empty]
  | map(select(.risk_level=="high" or .risk_level=="critical"))
  | {critical_repos: [.[] | .repo],
     total_findings: ([.[].findings[]] | length),
     cost_usd: ([$$COST_PLACEHOLDER] | .[0])}
' reports/*.json > summary.json
echo "完成。高风险仓库见 summary.json"
```

**3) 预期结果**

- `reports/<repo>.json`：每个仓库一份结构化报告，含 `risk_level`、`findings[]`。
- `summary.json`：高风险/critical 仓库清单、发现总数。
- 终端逐行打印 `[OK]/[FAIL]`，失败有独立 `.err` 可查。

**4) 常见问题与解决**

| 现象 | 原因 | 解决 |
| --- | --- | --- |
| 大量 `[FAIL]` + err 里 `rate_limit` | 并发过高触发限流 | 降 `-P` 到 2～3，或加退避 |
| `structured_output` 为空 | schema 太宽或仓库过大超 `--max-turns` | 调大 turns、收紧 schema、拆分仓库 |
| 账单高于预期 | 没设 `--max-budget-usd` | 每任务加预算上限 |
| 结果不稳定 | 未用 `--bare` | 全程 `--bare`，CI 可复现 |

---

## 整体工作流程

```mermaid
flowchart TD
    A["repos/ 多仓库目录"] --> B["find 遍历目录列表"]
    B --> C["xargs -P 4 并发扇出"]
    C --> D1["claude --bare -p\n+ allowedTools Read\n+ json-schema\n+ max-budget/turns"]
    C --> D2["claude --bare -p ..."]
    C --> D3["claude --bare -p ..."]
    D1 --> E1["reports/repo1.json"]
    D2 --> E2["reports/repo2.json"]
    D3 --> E3["reports/repo3.json"]
    E1 & E2 & E3 --> F["jq -s 汇总"]
    F --> G["summary.json\n高风险仓库 / 发现总数 / 成本"]
    G --> H["阈值告警 / 报表 / 数据库"]

    subgraph 单次调用生命周期
      I["system/init\n(model/tools/plugins)"] --> J["assistant 文本+工具循环"]
      J --> K{"可重试错误?"}
      K -- 是 --> L["system/api_retry\n(退避后重试)"] --> J
      K -- 否 --> M["result\n(total_cost_usd/duration)"]
    end
```

## 延伸阅读

- **Agent SDK（Python/TypeScript）**：需要工具审批回调、原生消息对象、`StructuredOutput` 强类型时，从 shell 升级到 SDK，获得与 `claude -p` 同源的 agent loop 与上下文管理。
- **Hooks 与 settings.json**：把"每次执行后自动归档报告""拦截危险工具"固化为 hook，而非每个脚本重写。
- **流式监控与裸模式组合**：`--bare` + `stream-json` + `jq` 实时过滤事件，构建带进度条的 TUI 监控。
- **`control_request`/`control_response` 协议**：实现自定义运行时权限审批（只读放行、写操作转人工）。
- **`--max-budget-usd` 全局账本**：在编排层累加 `total_cost_usd`，跨批任务做日/周预算熔断。

## 训练营适用性评估

- **适合类型**：DevOps/SRE 训练营、安全工程训练营、AI 工程化训练营、企业 CI/CD 进阶营。
- **难度**：中高。要求学员能写 shell 脚本、懂 JSON Schema、理解并发与限流。
- **教学时长**：建议 1 个全天（6 小时）——2 小时讲无头模式与结构化输出，2 小时讲会话续接与并行扇出，2 小时动手搭审计管道并调优限流。
- **考核点**：能独立产出可复现的批量审计脚本，正确解析 `structured_output`，并能解释 `--bare`、`--max-budget-usd`、`api_retry` 的作用。
- **前置**：先完成"Claude Code 入门 + 装通首个 CLI"轮次，确保学员已熟悉交互模式与基础 flag。

## 参考来源

1. [Run Claude Code programmatically — 官方 Headless 文档](https://code.claude.com/docs/en/headless) — `-p`、`--bare`、`--output-format`、`--json-schema`、`total_cost_usd`、后台任务宽限等权威说明。
2. [CLI reference — Claude Code Docs](https://code.claude.com/docs/en/cli-reference) — 全部 flag（`--session-id`/`--resume`/`--continue`/`--fork-session`/`--max-turns`）的完整参考。
3. [Claude Code Stream-JSON Protocol Reference — claudewerk](https://github.com/claudification/claudewerk/blob/main/docs/stream-json-protocol.md) — 逆向自 CC v2.1.16x 的 stream-json 输入/输出协议、control_request 握手与事件目录。
4. [Claude stream-json event cheatsheet — takopi](https://takopi.dev/reference/runners/claude/stream-json-cheatsheet/) — `system/init`、`api_retry`、`result` 等顶层事件字段速查。
5. [Claude Code Headless Mode: The Definitive Guide to claude -p — Build This Now](https://www.buildthisnow.com/blog/guide/development/claude-code-headless-mode) — `-p` 实战模式、jq 解析、stdin 管道与 SDK 迁移路径。

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
