8.2 脚本编写
在上一节中,我们学习了命令组合的基础知识。在本节中,我们将学习如何将这些命令组合封装成可重用的脚本,以便更高效地自动化各种任务。
脚本编写概述
脚本是将一系列命令和逻辑组合在一起的可执行文件。使用脚本可以:
- 提高效率 :自动化重复性任务
- 减少错误 :避免手动操作的错误
- 便于维护 :集中管理复杂的逻辑
- 易于分享 :方便与团队成员共享
Bash 脚本基础
1. 脚本结构
一个基本的 Bash 脚本包含以下元素:
bash
#### 示例:基本脚本结构
bash
#!/bin/bash
# 脚本描述
# 作者:Your Name
# 日期:2026-01-01
# 设置脚本选项
set -e # 遇到错误立即退出
set -u # 使用未定义变量时报错
set -o pipefail # 管道中任何命令失败都导致整个管道失败
# 定义变量
PROJECT_DIR="./myproject"
MODEL="sonnet"
# 定义函数
main() {
echo "开始执行脚本"
setup_environment
generate_code
run_tests
echo "脚本执行完成"
}
# 执行主函数
main
#### 脚本元素说明#!/bin/bash:Shebang 行,指定脚本解释器set -e:遇到错误立即退出set -u:使用未定义变量时报错set -o pipefail:管道中任何命令失败都导致整个管道失败#:注释符号
bash
### 2\. 变量和参数
#### 示例:定义和使用变量
bash
#!/bin/bash
# 定义变量
PROJECT_DIR="./myproject"
MODEL="sonnet"
OUTPUT_FORMAT="json"
VERBOSE=true
# 使用变量
echo "项目目录: $PROJECT_DIR"
echo "模型: $MODEL"
# 条件使用变量
if [ "$VERBOSE" = true ]; then
claude --model "$MODEL" -p "分析项目" --verbose
else
claude --model "$MODEL" -p "分析项目"
fi
#### 示例:使用位置参数
bash
#!/bin/bash
# 使用位置参数
PROJECT_DIR=$1
MODEL=${2:-sonnet} # 默认值为 sonnet
OUTPUT_FORMAT=${3:-json}
# 检查参数
if [ -z "$PROJECT_DIR" ]; then
echo "错误:必须指定项目目录"
echo "用法: $0 <项目目录> [模型] [输出格式]"
exit 1
fi
# 使用参数
claude --model "$MODEL" \
--add-dir "$PROJECT_DIR" \
-p "分析项目" \
--output-format "$OUTPUT_FORMAT"
#### 示例:使用命名参数
bash
#!/bin/bash
# 定义命名参数
while getopts "d:m:f:v" opt; do
case $opt in
d) PROJECT_DIR="$OPTARG" ;;
m) MODEL="$OPTARG" ;;
f) OUTPUT_FORMAT="$OPTARG" ;;
v) VERBOSE=true ;;
\?) echo "无效选项: -$OPTARG" >&2; exit 1 ;;
esac
done
# 设置默认值
PROJECT_DIR=${PROJECT_DIR:-./myproject}
MODEL=${MODEL:-sonnet}
OUTPUT_FORMAT=${OUTPUT_FORMAT:-json}
VERBOSE=${VERBOSE:-false}
# 使用参数
if [ "$VERBOSE" = true ]; then
echo "项目目录: $PROJECT_DIR"
echo "模型: $MODEL"
echo "输出格式: $OUTPUT_FORMAT"
fi
claude --model "$MODEL" \
--add-dir "$PROJECT_DIR" \
-p "分析项目" \
--output-format "$OUTPUT_FORMAT"
### 3\. 函数定义
#### 示例:定义和使用函数
bash
#!/bin/bash
# 定义函数
setup_environment() {
echo "设置环境..."
claude --add-dir ./src --add-dir ./tests --add-dir ./config
}
generate_code() {
echo "生成代码..."
claude -p "生成代码"
}
run_tests() {
echo "运行测试..."
claude -p "运行测试"
}
# 定义主函数
main() {
setup_environment
generate_code
run_tests
}
# 执行主函数
main
#### 示例:带参数的函数
bash
#!/bin/bash
# 定义带参数的函数
analyze_file() {
local file=$1
local model=${2:-sonnet}
echo "分析文件: $file"
claude --model "$model" -p "分析 $file 的代码质量"
}
# 使用函数
analyze_file main.py
analyze_file utils.js opus
#### 示例:带返回值的函数
bash
#!/bin/bash
# 定义带返回值的函数
get_model() {
local task_type=$1
case $task_type in
"code_review")
echo "sonnet"
;;
"generation")
echo "opus"
;;
*)
echo "sonnet"
;;
esac
}
# 使用函数
MODEL=$(get_model "code_review")
echo "使用的模型: $MODEL"
### 4\. 条件判断
#### 示例:if 语句
bash
#!/bin/bash
# 检查文件是否存在
if [ -f "config.json" ]; then
echo "配置文件存在"
claude -p "使用配置文件"
else
echo "配置文件不存在"
claude -p "使用默认配置"
fi
# 检查命令执行结果
if claude -p "检查代码质量"; then
echo "代码质量检查通过"
else
echo "代码质量检查失败"
exit 1
fi
# 多条件判断
if [ -f "config.json" ] && [ -f "settings.json" ]; then
echo "所有配置文件都存在"
elif [ -f "config.json" ]; then
echo "只有 config.json 存在"
else
echo "配置文件不存在"
fi
#### 示例:case 语句
bash
#!/bin/bash
# 使用 case 语句
TASK_TYPE=$1
case $TASK_TYPE in
"review")
echo "执行代码审查"
claude -p "审查代码"
;;
"test")
echo "执行测试"
claude -p "运行测试"
;;
"deploy")
echo "执行部署"
claude -p "部署应用"
;;
*)
echo "未知任务类型: $TASK_TYPE"
echo "支持的任务类型: review, test, deploy"
exit 1
;;
esac
### 5\. 循环结构
#### 示例:for 循环
bash
#!/bin/bash
# 遍历文件
for file in *.py; do
echo "处理文件: $file"
claude -p "优化 $file 的性能"
done
# 遍历数组
projects=("frontend" "backend" "api")
for project in "${projects[@]}"; do
echo "处理项目: $project"
claude --add-dir "./$project" -p "分析项目"
done
# 数字循环
for i in {1..5}; do
echo "执行第 $i 次迭代"
claude -p "执行任务 $i"
done
#### 示例:while 循环
bash
#!/bin/bash
# 持续监控文件变化
while inotifywait -e modify *.py; do
echo "检测到文件变化"
claude -p "重新分析代码"
done
# 读取文件内容
while IFS= read -r line; do
echo "处理行: $line"
claude -p "处理: $line"
done < input.txt
# 条件循环
count=0
while [ $count -lt 5 ]; do
echo "计数: $count"
claude -p "执行任务 $count"
((count++))
done
### 6\. 错误处理
#### 示例:基本错误处理
bash
#!/bin/bash
# 设置错误处理
set -e
# 检查命令是否成功
if ! claude -p "生成代码"; then
echo "错误:代码生成失败"
exit 1
fi
# 使用 trap 捕获错误
trap 'echo "发生错误,退出码: $?"' ERR
claude -p "执行任务1"
claude -p "执行任务2"
claude -p "执行任务3"
#### 示例:高级错误处理
bash
#!/bin/bash
# 定义错误处理函数
handle_error() {
local exit_code=$1
local line_number=$2
echo "错误发生在第 $line_number 行,退出码: $exit_code"
# 清理操作
cleanup
exit $exit_code
}
# 设置错误处理
trap 'handle_error $? $LINENO' ERR
# 定义清理函数
cleanup() {
echo "执行清理操作..."
rm -f temp_files/*
}
# 执行任务
claude -p "执行任务1"
claude -p "执行任务2"
claude -p "执行任务3"
# 清理
cleanup
## 实用脚本示例
### 1\. 代码审查脚本
bash
#!/bin/bash
# 代码审查脚本
# 用法: ./code_review.sh [文件或目录] [模型]
set -e
# 参数处理
TARGET=${1:-.}
MODEL=${2:-sonnet}
# 检查目标是否存在
if [ ! -e "$TARGET" ]; then
echo "错误:目标不存在: $TARGET"
exit 1
fi
# 检查是文件还是目录
if [ -f "$TARGET" ]; then
echo "审查文件: $TARGET"
claude --model "$MODEL" -p "审查 $TARGET 的代码质量、安全性和性能"
elif [ -d "$TARGET" ]; then
echo "审查目录: $TARGET"
claude --model "$MODEL" --add-dir "$TARGET" -p "审查目录中的所有文件"
else
echo "错误:不支持的目标类型"
exit 1
fi
### 2\. 自动化测试脚本
bash
#!/bin/bash
# 自动化测试脚本
# 用法: ./auto_test.sh [测试类型]
set -e
# 参数处理
TEST_TYPE=${1:-all}
# 定义测试函数
run_unit_tests() {
echo "运行单元测试..."
claude -p "生成单元测试用例"
claude -p "运行单元测试"
}
run_integration_tests() {
echo "运行集成测试..."
claude -p "生成集成测试用例"
claude -p "运行集成测试"
}
run_e2e_tests() {
echo "运行端到端测试..."
claude -p "生成端到端测试用例"
claude -p "运行端到端测试"
}
# 根据测试类型执行测试
case $TEST_TYPE in
"unit")
run_unit_tests
;;
"integration")
run_integration_tests
;;
"e2e")
run_e2e_tests
;;
"all")
run_unit_tests
run_integration_tests
run_e2e_tests
;;
*)
echo "错误:未知测试类型: $TEST_TYPE"
echo "支持的测试类型: unit, integration, e2e, all"
exit 1
;;
esac
echo "所有测试完成"
### 3\. 文档生成脚本
bash
#!/bin/bash
# 文档生成脚本
# 用法: ./generate_docs.sh [输出目录]
set -e
# 参数处理
OUTPUT_DIR=${1:-./docs}
# 创建输出目录
mkdir -p "$OUTPUT_DIR"
# 提取函数文档
echo "提取函数文档..."
claude -p "提取所有函数的文档注释" --output-format json > functions.json
# 提取类文档
echo "提取类文档..."
claude -p "提取所有类的文档注释" --output-format json > classes.json
# 生成 Markdown 文档
echo "生成 Markdown 文档..."
claude -p "根据提取的信息生成 Markdown 文档" \
--input-format json \
--output-format markdown \
> "$OUTPUT_DIR/API.md"
# 生成 HTML 文档
echo "生成 HTML 文档..."
claude -p "根据提取的信息生成 HTML 文档" \
--input-format json \
--output-format html \
> "$OUTPUT_DIR/API.html"
echo "文档生成完成: $OUTPUT_DIR"
### 4\. 项目分析脚本
bash
#!/bin/bash
# 项目分析脚本
# 用法: ./analyze_project.sh [项目目录] [输出格式]
set -e
# 参数处理
PROJECT_DIR=${1:-.}
OUTPUT_FORMAT=${2:-json}
# 检查项目目录
if [ ! -d "$PROJECT_DIR" ]; then
echo "错误:项目目录不存在: $PROJECT_DIR"
exit 1
fi
# 分析项目结构
echo "分析项目结构..."
claude --add-dir "$PROJECT_DIR" \
-p "分析项目结构、代码质量和潜在问题" \
--output-format "$OUTPUT_FORMAT" \
> "project_analysis.$OUTPUT_FORMAT"
# 生成报告
echo "生成分析报告..."
claude -p "根据分析结果生成详细的报告" \
--input-format "$OUTPUT_FORMAT" \
--output-format markdown \
> "project_report.md"
echo "项目分析完成"
echo "分析结果: project_analysis.$OUTPUT_FORMAT"
echo "分析报告: project_report.md"
### 5\. 批量处理脚本
bash
#!/bin/bash
# 批量处理脚本
# 用法: ./batch_process.sh [文件模式] [处理类型]
set -e
# 参数处理
FILE_PATTERN=${1:-*.py}
PROCESS_TYPE=${2:-optimize}
# 定义处理函数
optimize_files() {
for file in $FILE_PATTERN; do
echo "优化文件: $file"
claude -p "优化 $file 的性能" > "${file%.py}.optimized.py"
done
}
review_files() {
for file in $FILE_PATTERN; do
echo "审查文件: $file"
claude -p "审查 $file 的代码质量" > "${file%.py}.review.md"
done
}
refactor_files() {
for file in $FILE_PATTERN; do
echo "重构文件: $file"
claude -p "重构 $file 的代码结构" > "${file%.py}.refactored.py"
done
}
# 根据处理类型执行处理
case $PROCESS_TYPE in
"optimize")
optimize_files
;;
"review")
review_files
;;
"refactor")
refactor_files
;;
*)
echo "错误:未知处理类型: $PROCESS_TYPE"
echo "支持的处理类型: optimize, review, refactor"
exit 1
;;
esac
echo "批量处理完成"
## 脚本最佳实践
### 1\. 脚本组织
* **模块化** :将复杂脚本拆分成多个函数
* **配置化** :使用配置文件管理参数
* **文档化** :为脚本添加详细的注释和文档
#### 示例:模块化脚本
bash
#!/bin/bash
# 导入配置文件
source config.sh
# 导入函数库
source lib/functions.sh
# 主函数
main() {
initialize
execute_tasks
cleanup
}
# 执行主函数
main
### 2\. 错误处理- 设置错误处理 :使用
set -e和trap - 检查返回值 :检查命令的退出码
- 提供清晰的错误信息 :为用户提供有用的错误信息
bash
#### 示例:完善的错误处理
bash
#!/bin/bash
# 设置错误处理
set -e
set -u
set -o pipefail
# 定义错误处理函数
error_handler() {
local exit_code=$1
local line_number=$2
echo "错误: 脚本在第 $line_number 行失败,退出码: $exit_code"
cleanup
exit $exit_code
}
# 设置错误处理
trap 'error_handler $? $LINENO' ERR
# 定义清理函数
cleanup() {
echo "执行清理操作..."
rm -f temp_files/*
}
# 执行任务
main
### 3\. 日志记录- 记录执行过程 :记录脚本的执行过程
- 记录错误信息 :记录错误和警告信息
- 记录性能指标 :记录执行时间和资源使用情况
bash
#### 示例:日志记录
bash
#!/bin/bash
# 定义日志函数
log() {
local level=$1
shift
local message="$@"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" >> script.log
}
# 使用日志函数
log INFO "脚本开始执行"
log INFO "执行任务1"
claude -p "执行任务1"
log INFO "任务1完成"
log INFO "脚本执行完成"
### 4\. 性能优化
* **并行处理** :使用后台执行和 wait 提高效率
* **缓存结果** :避免重复执行相同的命令
* **增量处理** :只处理变化的部分
#### 示例:性能优化
bash
#!/bin/bash
# 并行处理多个文件
for file in *.py; do
claude -p "分析 $file" > "${file%.py}.analysis.json" &
done
wait
# 使用缓存
CACHE_FILE="analysis.cache"
if [ -f "$CACHE_FILE" ]; then
log INFO "使用缓存结果"
cat "$CACHE_FILE"
else
claude -p "分析项目" > "$CACHE_FILE"
fi
## 总结脚本编写是自动化 Claude Code 任务的关键技能。通过掌握 Bash 脚本的基础知识(变量、函数、条件判断、循环、错误处理)和实用脚本示例,您可以创建强大、可重用的自动化工具。
记住以下要点:
- 从简单开始 :先编写简单的脚本,逐步增加复杂性
- 注重实践 :通过实际项目练习脚本编写
- 遵循最佳实践 :使用错误处理、日志记录和性能优化
- 持续改进 :不断优化和改进您的脚本
在接下来的章节中,我们将学习如何将这些脚本集成到 CI/CD 流程中,以及如何进行批处理操作和实际工作流应用。