Claude Code的Headless模式(-p标志)远不止"无界面运行"这么简单——它是一套完整的会话生命周期管理系统。本教程深入讲解Headless模式的核心机制、会话续传(--continue/--resume)、结构化输出控制(--output-format)、权限自动化配置,以及生产级错误恢复策略。学完你将掌握用Shell脚本构建可靠、可恢复、可审计的AI自动化工作流。
适用人群:已有Claude Code基础使用经验的开发者、DevOps工程师、需要将AI能力嵌入CI/CD或定时任务的技术负责人。
| 项目 | 要求 |
|---|---|
| Claude Code | v1.0.18+(支持--output-format json) |
| Node.js | v18+ |
| 操作系统 | macOS / Linux(Windows需WSL2) |
| API Key | Anthropic API Key已配置 |
| 基础知识 | 熟悉Shell脚本、管道操作、JSON处理 |
安装验证:
claude --version
# 确保 >= 1.0.18
-p(--print)标志是所有Headless自动化的入口。它让Claude Code跳过交互式TUI界面,直接处理提示并输出结果到stdout:
# 最简形式:单次执行,输出到stdout
claude -p "列出src/目录下所有未使用TypeScript类型的文件"
# 管道输入:将内容通过stdin传入
git diff HEAD~5 | claude -p "为这些变更生成CHANGELOG条目"
# 组合使用:文件内容作为上下文
cat error.log | claude -p "分析错误日志,给出修复建议"
核心行为规则:
- 执行完毕自动退出,退出码0表示成功
- 工具调用(文件读写、Bash执行)照常运行
- 无需人类交互——默认使用settings.json中的权限配置
在自动化场景中,启动速度至关重要。--bare标志跳过所有启动发现过程:
# 普通Headless:需要加载hooks、skills、MCP发现
claude -p "检查代码风格" # 启动约2-5秒
# Bare模式:跳过hooks、skills自动发现、MCP初始化
claude -p --bare "检查代码风格" # 启动约0.5-1秒
--bare跳过的内容:
- Hooks自动发现和注册
- Skills目录扫描
- MCP服务器连接初始化
- 部分环境检测
何时用--bare:纯代码分析、日志解读、文本生成等不依赖MCP或自定义工具的轻量任务。
何时不用--bare:需要调用特定MCP工具、依赖Hooks触发器、或使用自定义Skills的任务。
Headless模式最强大的特性之一是结构化输出:
# 纯文本输出(默认)
claude -p "总结这个项目的架构" > summary.txt
# JSON输出:包含完整元数据
claude -p "分析package.json的依赖" \
--output-format json \
> analysis.json
# JSON输出 + Schema约束
claude -p "列出所有TODO注释" \
--output-format json \
--json-schema '{
"type": "object",
"properties": {
"todos": {
"type": "array",
"items": {
"type": "object",
"properties": {
"file": {"type": "string"},
"line": {"type": "integer"},
"text": {"type": "string"},
"priority": {"enum": ["high", "medium", "low"]}
},
"required": ["file", "line", "text"]
}
}
}
}'
JSON输出结构示例:
{
"result": "找到12个TODO注释...",
"cost_usd": 0.0034,
"duration_ms": 4521,
"num_turns": 2,
"session_id": "abc123def456",
"is_error": false
}
关键字段解读:
- session_id:后续用--resume恢复此会话的关键标识
- cost_usd:本次执行的精确Token费用
- num_turns:Agent循环的迭代次数,用于成本分析
- is_error:是否因错误退出
对于长时间运行的任务,流式输出提供实时反馈:
# 流式JSON输出
claude -p "重构整个auth模块" \
--output-format stream-json
# 每行输出一个JSON对象
# {"type":"assistant","content":"正在分析..."}
# {"type":"tool_use","tool":"Read","input":{"file_path":"src/auth.ts"}}
# {"type":"assistant","content":"发现3个问题..."}
流式输出的JSON Lines格式可用于构建进度监控:
# 实时显示进度,同时保存完整日志
claude -p "运行测试并修复失败的用例" \
--output-format stream-json \
2>/dev/null | while IFS= read -r line; do
type=$(echo "$line" | jq -r '.type // empty')
case "$type" in
"assistant") echo "🤖 $(echo "$line" | jq -r '.content[:80]')" ;;
"tool_use") echo "🔧 调用工具: $(echo "$line" | jq -r '.tool')" ;;
"tool_result") echo "✅ 工具结果: $(echo "$line" | jq -r '.content[:80]')" ;;
esac
done
Claude Code的每个Headless执行都创建一个会话,会话具有完整的生命周期:
stateDiagram-v2
[*] --> 创建: claude -p
创建 --> 活跃: Agent循环执行
活跃 --> 工具调用: 读取/编辑/执行
工具调用 --> 活跃: 返回结果
活跃 --> 挂起: 达到max-turns限制
活跃 --> 完成: 任务结束
挂起 --> 恢复: --resume session_id
完成 --> 续传: --continue
恢复 --> 活跃: 继续执行
续传 --> 活跃: 基于上次会话
完成 --> [*]
--continue(简写-c)加载最近一次会话的完整上下文:
# 第一步:初始分析
claude -p "分析src/api/目录的代码质量问题" \
--output-format json > step1.json
# 第二步:基于上一次会话继续,要求修复
claude -p --continue "根据上面的分析,修复所有高优先级问题" \
--output-format json > step2.json
# 第三步:验证修复
claude -p --continue "运行测试验证所有修复" \
--output-format json > step3.json
关键特性:
- --continue只能恢复最近一次会话
- 会话上下文包含之前的所有对话和工具调用结果
- 即使中间发生了其他交互式会话,-c仍然指向最后一次Headless会话
--resume(简写-r)通过session_id恢复任意历史会话:
# 从JSON输出中提取session_id
SESSION_ID=$(claude -p "分析代码覆盖率" \
--output-format json | jq -r '.session_id')
echo "会话ID: $SESSION_ID"
# ... 几小时后或几天后 ...
# 恢复该会话,继续工作
claude -p --resume "$SESSION_ID" \
"基于之前的覆盖率分析,为未覆盖的函数生成测试用例"
实际场景——长时间任务的分段执行:
#!/bin/bash
# 文件: incremental-refactor.sh
# 用途:大型重构的分段执行,每段限制20轮
TASK_DESCRIPTION="将所有class组件迁移为函数组件"
SESSION_FILE=".claude-refactor-session"
# 第一次执行或恢复
if [ -f "$SESSION_FILE" ]; then
SESSION_ID=$(cat "$SESSION_FILE")
echo "恢复会话: $SESSION_ID"
RESULT=$(claude -p --resume "$SESSION_ID" \
"继续迁移工作。上一次你迁移了哪些文件?继续剩余的。" \
--output-format json \
--max-turns 20)
else
echo "创建新会话"
RESULT=$(claude -p "$TASK_DESCRIPTION" \
--output-format json \
--max-turns 20)
fi
# 提取并保存session_id
NEW_SESSION=$(echo "$RESULT" | jq -r '.session_id')
echo "$NEW_SESSION" > "$SESSION_FILE"
# 检查是否完成
IS_ERROR=$(echo "$RESULT" | jq -r '.is_error')
NUM_TURNS=$(echo "$RESULT" | jq -r '.num_turns')
echo "本轮执行: ${NUM_TURNS}轮, 费用: \$(echo "$RESULT" | jq -r '.cost_usd')"
if [ "$IS_ERROR" = "true" ]; then
echo "执行出错,请检查日志"
exit 1
fi
if [ "$NUM_TURNS" -lt 20 ]; then
echo "任务已完成!清理会话文件。"
rm "$SESSION_FILE"
else
echo "达到轮次上限,运行此脚本继续下一阶段。"
fi
理解会话上下文包含什么,不包含什么:
| 上下文内容 | 是否保留 | 说明 |
|---|---|---|
| 对话历史 | 是 | 完整的提示和回复链 |
| 工具调用记录 | 是 | 读取的文件内容、执行的命令输出 |
| 文件系统变更 | 否 | 恢复的是对话记忆,不是文件快照 |
| 环境变量变更 | 否 | 每次执行都是新的Shell环境 |
| MCP连接状态 | 否 | 重新建立MCP连接 |
| 运行中进程 | 否 | 后台进程不会被恢复 |
关键洞察:会话恢复不是"时光机"——它恢复的是对话上下文,不是系统状态。如果之前的会话修改了文件,那些修改已经在磁盘上了;如果之前的会话启动了服务器,你需要重新启动它。
交互模式下,Claude Code遇到需要权限的操作会弹出确认。Headless模式下没有人类来点击"允许"——你需要预先配置权限。
精确控制Headless执行可以使用哪些工具:
# 只读分析:只允许读取和搜索
claude -p "审计src/目录的安全漏洞" \
--allowedTools "Read,Glob,Grep"
# 允许读取和编辑,但不允许执行Shell命令
claude -p "修复所有lint错误" \
--allowedTools "Read,Edit,Glob,Grep"
# 完全自动化:允许所有工具
claude -p "实现用户认证模块" \
--allowedTools "Bash,Read,Edit,Write,Glob,Grep"
工具名称完整列表:
- Read — 读取文件
- Edit — 编辑现有文件
- Write — 创建新文件
- Bash — 执行Shell命令
- Glob — 文件搜索
- Grep — 内容搜索
- Task — 启动子Agent
对于频繁执行的自动化任务,在项目级.claude/settings.json中预配置权限:
{
"permissions": {
"allow": [
"Read",
"Glob",
"Grep",
"Edit(src/**)",
"Bash(npm test*)",
"Bash(npm run lint*)",
"Bash(git diff*)",
"Bash(git log*)"
],
"deny": [
"Bash(rm -rf*)",
"Bash(git push*)",
"Bash(git reset*)",
"Write(.env*)",
"Write(*credentials*)"
]
}
}
模式匹配规则:
- Edit(src/**) — 允许编辑src/目录下的所有文件
- Bash(npm test*) — 允许所有以npm test开头的命令
- Write(.env*) — 拒绝写入任何以.env开头的文件
Claude Code提供三种全局权限模式:
# Plan模式:只读取不修改,适合分析
claude -p --permission-mode plan "分析代码架构并给出重构建议"
# Auto-accept模式:自动批准所有操作(危险!)
claude -p --permission-mode auto-accept "重构整个项目"
# 默认模式:根据settings.json配置
claude -p "常规开发任务"
生产环境推荐:
# 安全的CI审计模式
claude -p "检查PR的代码质量" \
--permission-mode plan \
--output-format json \
--max-turns 5
# 受限的修复模式
claude -p "修复测试失败" \
--allowedTools "Read,Edit,Bash(npm*,npx*)" \
--max-turns 10 \
--output-format json
每个Headless执行都应该设置三道安全边界:
claude -p "你的任务描述" \
--max-turns 15 \ # 阀门1:最大Agent循环轮次
--max-tokens 50000 \ # 阀门2:最大Token消耗
--timeout 300000 # 阀门3:最大执行时间(ms)
graph TD
A[Headless执行启动] --> B{max-turns检查}
B -->|未达上限| C{max-tokens检查}
B -->|已达上限| Z[停止: 轮次耗尽]
C -->|未达上限| D{timeout检查}
C -->|已达上限| Z2[停止: Token耗尽]
D -->|未超时| E[执行Agent循环]
D -->|已超时| Z3[停止: 时间到]
E --> F{任务完成?}
F -->|是| G[输出结果 + 退出码0]
F -->|否| B
这是最重要的安全参数。每次Agent循环("思考→调用工具→获取结果→再思考")算一轮:
# 轻量任务:1-3轮足够
claude -p "这个函数做了什么?" --max-turns 3
# 中等任务:5-15轮
claude -p "修复所有TypeScript类型错误" --max-turns 15
# 重量任务:15-30轮
claude -p "重构认证模块为OAuth2.0" --max-turns 30
# 禁止:不加限制的执行
# claude -p "重构整个项目" # 危险!可能无限循环
轮次规划公式:
预估轮次 = 文件数量 × 每文件操作数 × 安全系数(1.5)
示例:修复20个文件的lint错误
预估轮次 = 20 × 2(读取+编辑) × 1.5 = 60
设置 --max-turns 60
#!/bin/bash
# 文件: budget-guard.sh
# 用途:带预算控制的Headless执行
MAX_COST=0.50 # 单次执行最大费用(美元)
RESULT=$(claude -p "$1" \
--output-format json \
--max-turns 20)
# 提取费用
ACTUAL_COST=$(echo "$RESULT" | jq -r '.cost_usd')
SESSION_ID=$(echo "$RESULT" | jq -r '.session_id')
TURNS=$(echo "$RESULT" | jq -r '.num_turns')
echo "=== 执行报告 ==="
echo "会话ID: $SESSION_ID"
echo "轮次: $TURNS"
echo "费用: \$$ACTUAL_COST"
# 预算检查
if (( $(echo "$ACTUAL_COST > $MAX_COST" | bc -l) )); then
echo "⚠️ 费用超预算!上限: \$$MAX_COST, 实际: \$$ACTUAL_COST"
exit 2
fi
# 提取实际回答内容
echo "$RESULT" | jq -r '.result'
Headless执行的退出码承载重要信息:
| 退出码 | 含义 | 处理策略 |
|---|---|---|
| 0 | 成功完成 | 继续下一步 |
| 1 | 一般性错误 | 检查提示和权限 |
| 2 | 被安全限制终止 | 增加--max-turns或--timeout |
# 根据退出码做条件处理
claude -p "运行测试" --max-turns 10 --output-format json > result.json
EXIT_CODE=$?
case $EXIT_CODE in
0) echo "成功"; cat result.json | jq -r '.result' ;;
1) echo "执行出错"; cat result.json | jq -r '.result' ;;
2) echo "被限制终止,考虑增加限制或分段执行" ;;
esac
我们将构建一个完整的Headless任务运行器,具备以下能力:
graph LR
A[任务队列 JSON] --> B[任务调度器]
B --> C{会话存在?}
C -->|是| D[resume恢复]
C -->|否| E[新建会话]
D --> F[Claude -p 执行]
E --> F
F --> G{执行结果}
G -->|成功| H[保存结果 + 清理会话]
G -->|轮次耗尽| I[保存session_id + 排入重试队列]
G -->|错误| J[记录错误 + 人工通知]
H --> K[生成报告]
I --> B
J --> K
// 文件: tasks/queue.json
[
{
"id": "task-001",
"name": "安全审计",
"prompt": "扫描src/目录,检查SQL注入、XSS和其他OWASP Top 10漏洞。对每个漏洞给出文件名、行号、严重程度和修复建议。",
"allowedTools": ["Read", "Glob", "Grep"],
"maxTurns": 10,
"maxCost": 0.30,
"outputFormat": "json"
},
{
"id": "task-002",
"name": "生成API文档",
"prompt": "基于src/routes/目录的路由定义,生成OpenAPI 3.0规范的YAML文档。包含所有端点、请求/响应schema和示例。",
"allowedTools": ["Read", "Glob", "Grep", "Write"],
"maxTurns": 15,
"maxCost": 0.50,
"outputFormat": "json"
},
{
"id": "task-003",
"name": "测试覆盖率提升",
"prompt": "分析当前测试覆盖率报告,为覆盖率低于80%的模块生成新的测试用例。使用项目现有的测试框架。",
"allowedTools": ["Read", "Edit", "Write", "Bash", "Glob", "Grep"],
"maxTurns": 25,
"maxCost": 1.00,
"outputFormat": "json"
}
]
#!/bin/bash
# 文件: headless-runner.sh
# 用途:生产级Headless任务运行器
set -euo pipefail
# ==================== 配置 ====================
TASKS_FILE="${1:-tasks/queue.json}"
STATE_DIR=".headless-state"
REPORT_DIR="reports"
MAX_RETRIES=3
mkdir -p "$STATE_DIR" "$REPORT_DIR"
# ==================== 工具函数 ====================
# 获取任务状态文件路径
state_file() { echo "$STATE_DIR/$1.state.json"; }
# 检查任务是否完成
is_completed() {
local sf=$(state_file "$1")
[ -f "$sf" ] && [ "$(jq -r '.status' "$sf")" = "completed" ]
}
# 检查任务是否需要重试
needs_retry() {
local sf=$(state_file "$1")
[ -f "$sf" ] && [ "$(jq -r '.status' "$sf")" = "retry" ] && \
[ "$(jq -r '.retries' "$sf")" -lt "$MAX_RETRIES" ]
}
# 获取会话ID(用于续传)
get_session_id() {
local sf=$(state_file "$1")
if [ -f "$sf" ]; then
jq -r '.session_id // empty' "$sf"
fi
}
# ==================== 单任务执行 ====================
run_task() {
local task_json="$1"
local task_id=$(echo "$task_json" | jq -r '.id')
local task_name=$(echo "$task_json" | jq -r '.name')
local prompt=$(echo "$task_json" | jq -r '.prompt')
local max_turns=$(echo "$task_json" | jq -r '.maxTurns // 15')
local max_cost=$(echo "$task_json" | jq -r '.maxCost // 0.50')
local output_format=$(echo "$task_json" | jq -r '.outputFormat // "json"')
local tools=$(echo "$task_json" | jq -r '.allowedTools // [] | join(",")')
local sf=$(state_file "$task_id")
local session_id=""
local retries=0
# 恢复已有状态
if [ -f "$sf" ]; then
retries=$(jq -r '.retries // 0' "$sf")
session_id=$(jq -r '.session_id // empty' "$sf")
fi
echo "▶ 执行任务: $task_name (ID: $task_id, 重试: $retries)"
# 构建Claude命令
local cmd="claude -p"
# 会话续传或初始提示
if [ -n "$session_id" ]; then
echo " ↻ 恢复会话: $session_id"
cmd="$cmd --resume $session_id"
cmd="$cmd \"继续之前的任务。\""
else
# 转义prompt中的引号
local escaped_prompt=$(echo "$prompt" | sed 's/"/\\"/g')
cmd="$cmd \"$escaped_prompt\""
fi
# 工具限制
if [ -n "$tools" ]; then
cmd="$cmd --allowedTools \"$tools\""
fi
# 安全限制
cmd="$cmd --max-turns $max_turns"
cmd="$cmd --output-format $output_format"
# 执行并捕获结果
local result
set +e
result=$(eval "$cmd" 2>&1)
local exit_code=$?
set -e
# 解析结果
local actual_cost="0"
local actual_turns="0"
local new_session_id=""
local is_error="true"
if [ "$output_format" = "json" ]; then
actual_cost=$(echo "$result" | jq -r '.cost_usd // 0' 2>/dev/null || echo "0")
actual_turns=$(echo "$result" | jq -r '.num_turns // 0' 2>/dev/null || echo "0")
new_session_id=$(echo "$result" | jq -r '.session_id // empty' 2>/dev/null || echo "")
is_error=$(echo "$result" | jq -r '.is_error // true' 2>/dev/null || echo "true")
fi
# 成本检查
local cost_status="ok"
if (( $(echo "$actual_cost > $max_cost" | bc -l 2>/dev/null || echo "0") )); then
cost_status="over_budget"
fi
# 确定任务状态
local task_status="completed"
if [ "$exit_code" -ne 0 ]; then
task_status="retry"
elif [ "$is_error" = "true" ]; then
task_status="retry"
elif [ "$cost_status" = "over_budget" ]; then
task_status="retry"
fi
# 保存状态
cat > "$sf" <<EOF
{
"task_id": "$task_id",
"task_name": "$task_name",
"status": "$task_status",
"session_id": "$new_session_id",
"retries": $((retries + 1)),
"exit_code": $exit_code,
"cost_usd": $actual_cost,
"turns": $actual_turns,
"timestamp": "$(date -Iseconds)"
}
EOF
# 保存完整结果
echo "$result" > "$REPORT_DIR/${task_id}-result.json"
# 状态报告
case "$task_status" in
completed)
echo " ✅ 完成 | 轮次: $actual_turns | 费用: \$$actual_cost"
;;
retry)
echo " ⚠️ 需要重试 | 退出码: $exit_code | 重试: $((retries + 1))/$MAX_RETRIES"
;;
esac
return 0
}
# ==================== 主循环 ====================
echo "======================================"
echo " Claude Code Headless 任务运行器"
echo " 任务文件: $TASKS_FILE"
echo "======================================"
TOTAL_TASKS=$(jq 'length' "$TASKS_FILE")
COMPLETED=0
FAILED=0
TOTAL_COST=0
# 遍历所有任务
for i in $(seq 0 $((TOTAL_TASKS - 1))); do
task_json=$(jq ".[$i]" "$TASKS_FILE")
task_id=$(echo "$task_json" | jq -r '.id')
# 跳过已完成的任务
if is_completed "$task_id"; then
echo "⏭ 跳过已完成任务: $task_id"
COMPLETED=$((COMPLETED + 1))
continue
fi
# 检查重试次数
if [ -f "$(state_file "$task_id")" ]; then
retries=$(jq -r '.retries // 0' "$(state_file "$task_id")")
if [ "$retries" -ge "$MAX_RETRIES" ]; then
echo "❌ 任务 $task_id 已达最大重试次数,跳过"
FAILED=$((FAILED + 1))
continue
fi
fi
# 执行任务
run_task "$task_json"
# 统计
sf=$(state_file "$task_id")
if [ "$(jq -r '.status' "$sf")" = "completed" ]; then
COMPLETED=$((COMPLETED + 1))
fi
TOTAL_COST=$(echo "$TOTAL_COST + $(jq -r '.cost_usd // 0' "$sf")" | bc)
done
# ==================== 生成报告 ====================
echo ""
echo "======================================"
echo " 执行报告"
echo "======================================"
echo "总任务数: $TOTAL_TASKS"
echo "已完成: $COMPLETED"
echo "失败: $FAILED"
echo "总费用: \$$TOTAL_COST"
echo ""
# 生成JSON报告
jq -n \
--arg total "$TOTAL_TASKS" \
--arg completed "$COMPLETED" \
--arg failed "$FAILED" \
--arg cost "$TOTAL_COST" \
--arg timestamp "$(date -Iseconds)" \
'{
total_tasks: ($total | tonumber),
completed: ($completed | tonumber),
failed: ($failed | tonumber),
total_cost_usd: ($cost | tonumber),
timestamp: $timestamp
}' > "$REPORT_DIR/summary.json"
echo "报告已保存到: $REPORT_DIR/"
# 赋予执行权限
chmod +x headless-runner.sh
# 执行所有任务
./headless-runner.sh tasks/queue.json
# 查看某个任务的结果
cat reports/task-001-result.json | jq -r '.result'
# 查看执行摘要
cat reports/summary.json | jq .
# 重新运行未完成的任务(已完成的会自动跳过)
./headless-runner.sh tasks/queue.json
利用Shell的后台任务实现并行:
#!/bin/bash
# 文件: parallel-runner.sh
# 用途:并行执行多个独立任务
MAX_PARALLEL=3 # 最大并行数
RUNNING=0
run_with_limit() {
while [ "$(jobs -r | wc -l)" -ge "$MAX_PARALLEL" ]; do
sleep 5
done
eval "$1" &
}
# 定义并行任务
TASKS=(
'claude -p "扫描src/的安全漏洞" --allowedTools "Read,Glob,Grep" --max-turns 10 --output-format json > reports/security.json'
'claude -p "分析代码复杂度" --allowedTools "Read,Glob,Grep" --max-turns 8 --output-format json > reports/complexity.json'
'claude -p "检查依赖版本过期" --allowedTools "Read,Bash(npm*)" --max-turns 5 --output-format json > reports/deps.json'
'claude -p "生成API文档" --allowedTools "Read,Glob,Grep,Write" --max-turns 15 --output-format json > reports/api-docs.json'
)
for task in "${TASKS[@]}"; do
run_with_limit "$task"
done
# 等待所有任务完成
wait
echo "所有并行任务完成"
将Headless执行嵌入cron实现定期自动化:
# 编辑crontab
crontab -e
# 每天凌晨2点执行代码审查
0 2 * * * cd /path/to/project && claude -p "审查最近24小时的代码提交,检查潜在问题" --allowedTools "Read,Glob,Grep,Bash(git*)" --max-turns 15 --output-format json > /var/log/claude-review-$(date +\%Y\%m\%d).json
# 每周一生成架构文档
0 3 * * 1 cd /path/to/project && claude -p "更新项目架构文档,反映最新代码结构" --allowedTools "Read,Glob,Grep,Write" --max-turns 20 --output-format json > /var/log/claude-arch-$(date +\%Y\%m\%d).json
通过会话续传实现复杂的多步骤自动化:
#!/bin/bash
# 文件: chain-workflow.sh
# 用途:链式执行——上一步的输出是下一步的输入
set -euo pipefail
echo "=== 第1步:代码分析 ==="
STEP1=$(claude -p "分析src/目录的代码质量,列出前10个最需要改进的文件和具体问题" \
--allowedTools "Read,Glob,Grep" \
--max-turns 10 \
--output-format json)
SESSION=$(echo "$STEP1" | jq -r '.session_id')
echo "分析完成,会话ID: $SESSION"
echo "=== 第2步:制定修复计划 ==="
STEP2=$(claude -p --resume "$SESSION" \
"基于上面的分析,为每个问题制定具体的修复方案。输出为JSON格式,包含file、issue、fix字段。" \
--max-turns 10 \
--output-format json)
echo "修复计划完成"
echo "=== 第3步:执行修复 ==="
STEP3=$(claude -p --resume "$SESSION" \
"按照修复方案逐个修复。每修复一个文件后运行相关测试确认没有破坏功能。" \
--allowedTools "Read,Edit,Write,Bash(npm*),Glob,Grep" \
--max-turns 30 \
--output-format json)
echo "修复完成,费用: \$(echo "$STEP3" | jq -r '.cost_usd')"
echo "=== 第4步:验证 ==="
STEP4=$(claude -p --resume "$SESSION" \
"运行完整测试套件,确认所有修复没有引入新问题。给出最终报告。" \
--allowedTools "Read,Bash(npm*),Glob,Grep" \
--max-turns 5 \
--output-format json)
echo "$STEP4" | jq -r '.result'
echo "=== 工作流完成 ==="
echo "总费用: \$(echo "$STEP4" | jq -r '.cost_usd')"
#!/bin/bash
# 文件: resilient-exec.sh
# 用途:带自动恢复的Headless执行
execute_with_recovery() {
local prompt="$1"
local max_attempts=3
local attempt=1
local session_id=""
while [ "$attempt" -le "$max_attempts" ]; do
echo "尝试 $attempt/$max_attempts..."
local cmd="claude -p"
if [ -n "$session_id" ]; then
cmd="$cmd --resume $session_id"
cmd="$cmd \"上一次执行遇到问题,请继续完成任务。检查之前的操作是否完整。\""
else
cmd="$cmd \"$prompt\""
fi
cmd="$cmd --max-turns 15 --output-format json"
local result
set +e
result=$(eval "$cmd" 2>&1)
local exit_code=$?
set -e
session_id=$(echo "$result" | jq -r '.session_id // empty' 2>/dev/null || echo "")
local is_error=$(echo "$result" | jq -r '.is_error // true' 2>/dev/null || echo "true")
if [ "$exit_code" -eq 0 ] && [ "$is_error" = "false" ]; then
echo "执行成功"
echo "$result" | jq -r '.result'
return 0
fi
echo "执行失败 (退出码: $exit_code)"
echo "错误信息: $(echo "$result" | jq -r '.result' 2>/dev/null | head -5)"
attempt=$((attempt + 1))
if [ "$attempt" -le "$max_attempts" ]; then
echo "等待10秒后重试..."
sleep 10
fi
done
echo "所有尝试均失败"
return 1
}
# 使用
execute_with_recovery "为UserService添加完整的CRUD接口和对应的单元测试"
问题:长链式会话的上下文可能超出Token限制。
解决方案:
# 不要无限续传,定期创建新会话并总结
# 每5次续传后,总结当前状态,开启新会话
# 步骤1-N:正常续传
# 步骤N+1:总结并开启新会话
claude -p "总结当前项目的重构状态:已完成什么、还剩什么、下一步做什么" \
--resume "$OLD_SESSION" \
--output-format json | jq -r '.result' > /tmp/summary.txt
# 新会话,以总结作为上下文
claude -p "$(cat /tmp/summary.txt)\n\n基于以上状态,继续完成剩余工作。" \
--output-format json
问题:非UTF-8环境的输出可能乱码。
解决方案:
# 强制UTF-8环境
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
# 或在脚本开头
# -*- coding: utf-8 -*-
问题:Headless模式下权限被拒绝不会报错,只是工具不执行。
解决方案:
# 始终检查JSON输出的is_error字段
claude -p "修改配置文件" --output-format json | \
jq 'if .is_error then error("执行失败: \(.result)") else . end'
问题:多个Headless实例同时运行可能触发API限速。
解决方案:
# 控制并行数,避免并发超过3
MAX_CONCURRENT=3
# 使用flock实现互斥
for task in "${TASKS[@]}"; do
while [ "$(jobs -r | wc -l)" -ge "$MAX_CONCURRENT" ]; do
sleep 10
done
(
flock -x 200
eval "$task"
) 200>/tmp/claude-concurrent.lock &
done
# 启用verbose输出
claude -p "你的任务" --verbose --output-format json 2>debug.log
# debug.log包含:
# - Agent循环的每一步推理
# - 工具调用的完整参数和返回
# - Token使用统计
# - 上下文窗口状态
#!/bin/bash
# 分析多个任务的执行效率
for report in reports/*-result.json; do
jq -s '{
task: .[0].session_id[:8],
turns: .[0].num_turns,
cost: .[0].cost_usd,
cost_per_turn: (.turns > 0 | (.cost / .turns) | . * 100 | round / 100)
}' "$report" 2>/dev/null
done | jq -s 'sort_by(.cost_per_turn) | {
tasks: .,
avg_cost_per_turn: (map(.cost_per_turn) | add / length),
total_cost: (map(.cost) | add)
}'
| 维度 | 评估 |
|---|---|
| 适合训练营类型 | DevOps自动化训练营、AI工程化训练营、生产级AI集成课程 |
| 教学时长 | 4-5小时(含实操) |
| 难度等级 | 中高级 |
| 前置要求 | Claude Code基础使用、Shell脚本编写、JSON处理 |
| 实操占比 | 70%实操 + 30%理论 |
| 硬件要求 | 每人需要Anthropic API Key和稳定的网络环境 |
[!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 等场景全覆盖。
