本教程聚焦 Claude Code 的无头自动化能力:用 -p(print 模式)把 Claude 变成可被脚本调用的"无界面引擎",用 --output-format json --json-schema 让它吐出机器可读的结构化结果,再配一个调度脚本实现跨多文件的批量代码审查,最后用 hooks 给流水线加上确定性的质量门禁与成本核算。学完你能搭出一条"喂一批文件 → 并行审查 → 结构化聚合 → 一份报告"的命令行流水线。适合已经能用交互式 Claude Code、想把重复任务自动化的开发者与工程效能同学。
claude --version 能输出版本号,建议 v2.1.128 以上以获得 --json-schema 与 10MB stdin 限制等特性)jq(jq --version),用于解析 JSON 输出xargs、for 循环ANTHROPIC_API_KEY 已配置,或已通过 claude 登录交互式 Claude Code 是给人看的;脚本化场景要的是"给一句 prompt、拿一个可解析的结果"。-p(或 --print)就是这把钥匙。它的三种 --output-format 决定了你怎么消费结果:
# 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 让你给 Claude 一份 JSON Schema,它会强制把答案塞进这个结构,结果出现在 structured_output 字段里。这一步是把"会读代码的助手"变成"会填表的工人"的关键。
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 报告。
#!/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 '{}'),别让单点失败拖垮整批。
批量审查是只读的,用 --bare 没问题。但如果下一步你想让 Claude 批量自动修复问题并落盘,就需要 Edit/Write 工具,这时候 hooks(如编辑后自动格式化)才派得上用场。这里有一个最容易踩的坑:
--bare会跳过所有 hooks,因为它根本不读配置。要让 hook 生效,要么不用--bare,要么用--settings显式注入。
下面给自动修复场景配一个 PostToolUse 钩子:每次 Edit/Write 之后自动跑格式化。把它写进项目的 .claude/settings.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,并显式带上工具白名单:
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 能逐行吐事件,让你边跑边看进度;而每个 json 输出里的 total_cost_usd 让你能在报告里直接核算总花费。把审查脚本改造一下,加一个进度探针:
# 实时流式 + 只取最终 result 事件,同时累计成本
claude --bare -p "审查 src/payments.py" \
--allowedTools "Read" \
--output-format stream-json --verbose \
| jq -rc --unbuffered 'select(.type=="assistant")'
整批跑完后,前面脚本里已经用 jq -sr '[.[].cost]|add' 算出了总成本。这就形成闭环:每条结果带成本 → 聚合时求和 → 报告里直接显示花了多少钱,无需登录后台。
假设你有一个微服务仓库,src/ 下有十几个模块,安全同学让你一次性把"硬编码密钥、SQL 拼接、未校验输入"扫一遍并出报告。
batch-review.sh。./batch-review.sh 'src/**/*.py' 6,并发 6 跑起来。tail -f .claude/audit.log(如果你启用了 Stop 钩子)或观察脚本滚动输出。report.md:顶部是统计(文件数、高危数、总成本),下面是按高危优先排序的问题表格,每行带 文件:行 可直接跳转。--bare 以触发格式化钩子),用 --resume 或 --continue 在同一 session 里继续追问修复是否彻底。这条流水线的妙处在于:审查(只读、bare、快且确定) 与 修复(可写、带 hooks、强制质量门禁) 用两种配置分开处理,既快又稳。
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,可以做出"可中断、可续跑"的批量任务,适合跑一晚上都没跑完的超大批次。/loop 与定时任务)能力。-p,避免互相污染工作区。-p / --bare / --output-format / --json-schema 与成本字段、stdin 上限、后台任务等待上限的权威说明。PostToolBatch 等事件定义。if 字段的可用示例。-p 在 CI/CD、脚本编排与管道集成场景的补充实践。--print --output-format 在真实脚本中绕过 TUI、做结构化消费的工程经验。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
StructuredOutput 强类型时,从 shell 升级到 SDK,获得与 claude -p 同源的 agent loop 与上下文管理。--bare + stream-json + jq 实时过滤事件,构建带进度条的 TUI 监控。control_request/control_response 协议:实现自定义运行时权限审批(只读放行、写操作转人工)。--max-budget-usd 全局账本:在编排层累加 total_cost_usd,跨批任务做日/周预算熔断。structured_output,并能解释 --bare、--max-budget-usd、api_retry 的作用。-p、--bare、--output-format、--json-schema、total_cost_usd、后台任务宽限等权威说明。--session-id/--resume/--continue/--fork-session/--max-turns)的完整参考。system/init、api_retry、result 等顶层事件字段速查。-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 等场景全覆盖。
