本教程聚焦 Claude Code 的 裸模式(--bare)+ 流式输出(--output-format stream-json) 组合,带你从零搭建一条确定性、可监控、可计费的 -p 批处理流水线。学完你将掌握:为什么 CI 里必须用 --bare、如何用 --json-schema 拿到可直接入库的结构化结果、如何用流式事件做实时进度与成本看板、以及如何用权限规则锁死自动化边界。适合已会基础 -p 调用、想把 Claude Code 真正塞进生产流水线的工程师与 DevOps。
claude --version 能输出版本号,建议 v2.1.182 以上,以获得本文提到的后台等待上限等特性)ANTHROPIC_API_KEY 环境变量(裸模式下不再读取 OAuth/钥匙串)jq(流式事件解析必备)git(用于读取被处理文件、限定会话作用域)bash 的环境(Linux/macOS,或 WSL/Git Bash)-p 不适合进流水线很多人第一版自动化长这样:
claude -p "总结 docs/a.md" > out.txt
它能跑,但放进 CI 后会出现三类问题:
-p 默认会像交互式会话一样,加载工作目录与 ~/.claude 下的全部 hooks、skills、plugins、MCP 服务器、auto memory、CLAUDE.md。同事 A 的机器上跑出结果 X,CI 容器里跑出结果 Y,无法复现。这三个痛点,分别对应三个解药:--bare、stream-json、--json-schema。
--bare 锁定确定性--bare 是为脚本和 SDK 调用设计的模式,启动时跳过自动发现 hooks、skills、plugins、MCP、auto memory、CLAUDE.md。它的价值不是"快",而是"只有你显式传入的东西才生效"——这正是 CI 想要的可复现性。
# 裸模式跑一次性摘要,预批准 Read 工具,避免权限弹窗中断
claude --bare -p "Summarize this file" --allowedTools "Read" < docs/a.md
关键变化:上下文不再靠"它在硬盘上",而靠你用 flag 显式喂进去。 裸模式下能加载的内容与对应开关:
| 想加载的东西 | 使用的 flag |
|---|---|
| 系统提示补充 | --append-system-prompt、--append-system-prompt-file |
| 完整替换系统提示 | --system-prompt |
| 配置(含权限、apiKeyHelper) | --settings <file-or-json> |
| MCP 服务器 | --mcp-config <file-or-json> |
| 自定义子代理 | --agents <json> |
| 插件 | --plugin-dir <path>、--plugin-url <url> |
鉴权陷阱:裸模式跳过 OAuth 与钥匙串读取,鉴权必须来自 ANTHROPIC_API_KEY 或 --settings 里 JSON 的 apiKeyHelper。Bedrock/Vertex/Foundry 仍用各自厂商凭证。漏掉这一步,CI 里会直接鉴权失败。
export ANTHROPIC_API_KEY="sk-ant-..."
# 把领域规则作为系统提示注入,保证每台机器行为一致
claude --bare -p "审查这段代码的安全风险" \
--append-system-prompt "你是安全工程师。只输出 JSON:{risk, items[]}。" \
--allowedTools "Read" \
< src/auth.py
官方说明:
--bare是脚本/SDK 调用的推荐模式,未来会成为-p的默认行为。早点迁移,等于提前为下一次大版本升级免疫。
ANTHROPIC_API_KEY。/skill-name 不生效。原因:裸模式不自动发现 skills。解决:要么用 --plugin-dir/--agents 显式带,要么把 skill 指令直接写进 --append-system-prompt。--json-schema 拿结构化结果纯文本结果靠正则切迟早翻车。--output-format json 配合 --json-schema,能让模型按你给的 JSON Schema 返回,结果落在 structured_output 字段,可直接入库或喂给下游。
claude -p "提取 auth.py 里的函数名" \
--output-format json \
--json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}' \
| jq '.structured_output.functions'
--output-format json 的返回体还自带计费元数据,无需去用量后台查:
result:纯文本结果session_id:会话 ID(用于 --resume 续跑)total_cost_usd:本次调用总花费(美元)structured_output:按 --json-schema 校验后的结构化结果用 jq 取字段的标准姿势:
# 取文本结果
claude -p "总结这个项目" --output-format json | jq -r '.result'
# 取结构化结果
claude -p "提取函数名" --output-format json --json-schema '...' | jq '.structured_output'
structured_output 为空或报 schema 错。原因:模型输出未严格匹配 schema。解决:schema 尽量宽松(少用 additionalProperties:false),并在 --append-system-prompt 里明确"只输出符合 schema 的 JSON"。cat | claude。stream-json 造实时监控--output-format stream-json 会把模型工作过程按事件逐行(newline-delimited JSON)吐出来。配 --verbose 和 --include-partial-messages,连逐 token 的文本增量都能拿到。
claude -p "解释递归" --output-format stream-json --verbose --include-partial-messages
每行是一个 JSON 事件。最常用的两类:
1. 文本增量(实时打印正在生成的文字):
claude -p "写一首诗" --output-format stream-json --verbose --include-partial-messages \
| jq -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'
-rj 的含义:-r 输出原始字符串(去掉引号),-j 不补换行,于是 token 连续流式打印。
2. API 重试事件——这是批处理监控的隐藏宝石。当请求遇到可重试错误,Claude Code 会先发一个 system/api_retry 事件再重试。字段如下:
| 字段 | 类型 | 说明 |
|---|---|---|
type |
"system" |
消息类型 |
subtype |
"api_retry" |
标识为重试事件 |
attempt |
int | 当前重试序号,从 1 起 |
max_retries |
int | 允许的总重试次数 |
retry_delay_ms |
int | 距下次重试的毫秒数 |
error_status |
int/null | HTTP 状态码,连接级错误为 null |
error |
string | 错误类别 |
error 类别枚举包括:authentication_failed、oauth_org_not_allowed、billing_error、rate_limit、overloaded、invalid_request、model_not_found、server_error、max_output_tokens、unknown。
监控重试的意义:批处理跑到一半遇到 rate_limit,你能立刻看到"正在第 2 次重试,等 1200ms",而不是干等到超时。
无人值守必须明确"能干什么、不能干什么"。两条路径:
路径 A:白名单具体工具
claude -p "跑测试并修复失败" --allowedTools "Bash,Read,Edit"
--allowedTools 用的是权限规则语法,支持前缀匹配:
claude -p "看暂存改动并生成合适 commit" \
--allowedTools "Bash(git diff *),Bash(git log *),Bash(git status *),Bash(git commit *)"
细节坑:
Bash(git diff *)里星号前的空格不能省。写成Bash(git diff*)会把git diff-index也匹配进去。
路径 B:设整局权限模式
acceptEdits:允许写文件,且自动批准 mkdir、touch、mv、cp 等常见文件系统命令;其他 shell 命令与网络请求仍需显式 --allowedTools 或 permissions.allow 规则,否则尝试时直接中止。dontAsk:除了 permissions.allow 规则和只读命令集,其余一律拒绝——锁死 CI 的首选。claude -p "应用 lint 修复" --permission-mode acceptEdits
续跑:--continue 续最近一次会话;--resume <session-id> 续指定会话。
session_id=$(claude -p "开始一次审查" --output-format json | jq -r '.session_id')
claude -p "继续那次审查" --resume "$session_id"
注意:两条命令必须在同一目录运行——会话 ID 的查找作用域限定在当前项目目录及其 git worktree。
后台任务收尾(v2.1.163/v2.1.182 关键变更):若 -p 运行期间起了后台 Bash 任务(如 dev server),它会在返回最终结果、stdin 关闭后约 5 秒被终止。后台子代理/workflow 不受 5 秒限制(其结果是最终输出的一部分),但从 v2.1.182 起,这个等待默认上限 10 分钟,防止卡死的后台代理把进程无限期挂住。
# 调整后台等待上限(毫秒);设 0 表示无限等待
export CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=600000
下面这条流水线把前面四块拼起来:对 src/ 下每个 .py 文件跑一次裸模式安全扫描,流式打印进度与重试,用 --json-schema 拿结构化结果,最后汇总总成本。保存为 sec-scan.sh:
#!/usr/bin/env bash
# 用法: ./sec-scan.sh 'src/**/*.py' 并发数
set -euo pipefail
GLOB="${1:-'src/**/*.py'}"; CONCURRENCY="${2:-4}"
export ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY:?需要 ANTHROPIC_API_KEY}"
SCHEMA='{"type":"object","properties":{
"risk":{"type":"string","enum":["low","medium","high"]},
"issues":{"type":"array","items":{"type":"string"}}
},"required":["risk","issues"]}'
scan_one() {
local f="$1"
# 裸模式 + 结构化输出 + 流式事件
claude --bare -p "审查 $f 的安全风险,只按 schema 输出" \
--append-system-prompt "你是安全工程师,只输出符合 schema 的 JSON。" \
--allowedTools "Read" \
--output-format stream-json --verbose \
--json-schema "$SCHEMA" \
> "/tmp/scan-events/$$.jsonl" 2>/dev/null
# 解析事件:实时打印重试,最终取结构化结果与成本
jq -r 'select(.subtype=="api_retry") | " ⚠ 重试 #\(.attempt)/\(.max_retries) \(.error) 等\(.retry_delay_ms)ms"' \
"/tmp/scan-events/$$.jsonl" >&2
local risk cost
risk=$(jq -r 'select(.type=="result") | .structured_output.risk // "?"' "/tmp/scan-events/$$.jsonl" | tail -1)
cost=$(jq -r 'select(.type=="result") | .total_cost_usd // 0' "/tmp/scan-events/$$.jsonl" | tail -1)
printf '%s\t%s\t$%s\n' "$f" "$risk" "$cost"
}
export -f scan_one; export SCHEMA
mkdir -p /tmp/scan-events
echo "=== 开始扫描,并发=$CONCURRENCY ==="
# 用 xargs -P 做并行扇出,每行一个文件
find src -name '*.py' -print0 \
| xargs -0 -P "$CONCURRENCY" -I{} bash -c 'scan_one "$@"' _ {} \
| tee /tmp/scan-results.tsv
echo "=== 汇总 ==="
# 总成本
awk -F'\t' '{s+=$3} END{printf "扫描文件: %d 总成本: $%.4f\n", NR, s}' /tmp/scan-results.tsv
# 风险分布
awk -F'\t' '{c[$2]++} END{for(r in c) printf " %s: %d 个\n", r, c[r]}' /tmp/scan-results.tsv
预期输出(节选):
=== 开始扫描,并发=4 ===
⚠ 重试 #1/10 rate_limit 等1500ms
src/auth.py high $0.0123
src/utils.py low $0.0045
src/db.py medium $0.0089
=== 汇总 ===
扫描文件: 3 总成本: $0.0257
high: 1 个
low: 1 个
medium: 1 个
为什么这样设计:
--bare 让结果与运行机器无关,CI 上和同事本地结果一致;--allowedTools "Read" 配合 dontAsk/acceptEdits 思路,把扫描器限制成只读,绝不改你的代码;--json-schema 让 risk/issues 可直接 tee 成 TSV,再喂给告警系统;stream-json + jq 把"看不见的黑盒"变成"实时重试提示 + 逐文件成本",批处理不再是闷头等待;xargs -P 提供廉价并行,吞吐随并发线性增长(注意 rate_limit,过高并发会触发重试,反而变慢)。type=="result" 才是完整结果,务必 tail -1,避免取到中间增量。api_retry 的 error 若频繁是 rate_limit/overloaded,说明撞限流。降低 -P,或加自己的退避(看到 rate_limit 就 sleep)。--bare 卡住:检查 ANTHROPIC_API_KEY 是否注入;裸模式不读交互登录态。flowchart LR
subgraph 输入
F[文件列表 src/*.py]
end
subgraph Worker["裸模式 Worker --bare"]
P[prompt]
SP["--append-system-prompt\n领域指令"]
AT["--allowedTools Read\n只读边界"]
JS["--json-schema\n结构化契约"]
end
subgraph 流式监控["--output-format stream-json"]
E1[text_delta 逐 token]
E2["system/api_retry\n重试/限流"]
E3["result\nstructured_output\ntotal_cost_usd"]
end
subgraph 输出
TSV[scan-results.tsv]
SUM[成本/风险汇总]
end
F --> Worker
P --> Worker
SP --> Worker
AT --> Worker
JS --> Worker
Worker -->|逐行事件| 流式监控
E1 -->|jq 实时打印| 流式监控
E2 -->|jq 重试告警| 流式监控
E3 -->|jq 取字段| TSV
TSV --> SUM
SUM -.->|不达预期可 --resume 续跑| Worker
整条链路的可复现性由 --bare 保证(左侧只允许显式输入),可观测性由 stream-json 保证(中间三类事件),可解析性由 --json-schema 保证(右侧结构化落盘)。三者各管一头,缺一不可。
当你从"一个脚本"走向"团队工具"时,几个叠加项值得投入:
--settings 固化团队基线:把权限规则、apiKeyHelper、默认模型写进一份 JSON,所有人/CI 用同一个 --settings team.json,比各自 ~/.claude 更可控。--mcp-config 带上团队 MCP:扫描器需要查漏洞库?把 MCP 服务器定义进 --mcp-config vulns.json,裸模式下显式加载,不依赖本地 .mcp.json。--agents 注入专业子代理:复杂审查可拆成"OWASP 子代理"+"依赖审计子代理",用 --agents 声明,让主代理自动委派。session_id 落盘,失败项用 --resume 精准重跑,不必整批重来。total_cost_usd,超过阈值就停止派发新任务,避免一次跑飞烧光额度。| 维度 | 评估 |
|---|---|
| 适合的训练营类型 | DevOps/SRE 进阶营、AI 工程化实战营、企业 AI 落地营 |
| 学员基础 | 已掌握 Claude Code 基础 -p 调用与 shell 脚本 |
| 教学时长 | 建议 3 课时:1 课时讲 --bare/schema 理论,1 课时流式监控实操,1 课时产品化与排障 |
| 动手比重 | 高,全部步骤可直接在学员机器复现 |
| 易踩坑点 | 鉴权(API Key)、Bash(git diff *) 空格、流式结果取 tail -1、并发限流 |
核心要点:本教程的差异化在于把"裸模式确定性 + 结构化契约 + 流式可观测"作为一个整体工程来讲,而非单点介绍某个 flag。学员落地后能得到的是一条能在 CI 复现、能给老板报成本、能实时看到卡在哪的流水线,这正是把 Claude Code 从"玩具"推向"生产工具"的临门一脚。
https://code.claude.com/docs/en/cli-reference-p 更强的程序化控制):官方文档 Agent SDK 章节-p 在自动化场景的常见用法[!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 等场景全覆盖。
