最佳实践
设计原则
1. KISS原则 (Keep It Simple, Stupid)
❌ 错误: 创建复杂的配置系统,需要学习新的DSL
✅ 正确: 用简单的bash脚本和JSON配置
示例:
# 简单有效
function dev() {
cd ~/Developer/$1 && code . && npm run dev
}
# 过度设计
function dev() {
validate_project $1
load_config $1
setup_environment $1
initialize_services $1
configure_editor $1
...
}
2. DRY原则 (Don't Repeat Yourself)
# ❌ 重复代码
function deploy-staging() {
npm test
npm run build
scp -r dist/ staging:/var/www/
}
function deploy-production() {
npm test
npm run build
scp -r dist/ production:/var/www/
}
# ✅ 复用代码
function deploy() {
local env=$1
npm test || return 1
npm run build
case $env in
staging)
scp -r dist/ staging:/var/www/
;;
production)
scp -r dist/ production:/var/www/
;;
esac
}
3. 渐进增强
阶段1: 手动操作 → 记录步骤
阶段2: 写成脚本 → 简化执行
阶段3: 添加参数 → 增加灵活性
阶段4: 错误处理 → 提高可靠性
阶段5: 智能优化 → AI辅助
不要一开始就追求完美!
4. 故障优雅降级
# ✅ 有降级方案
function smart_commit() {
# 尝试AI生成
if command -v claude-cli &> /dev/null; then
msg=$(git diff --cached | claude-cli "Generate commit message")
if [ $? -eq 0 ]; then
git commit -m "$msg"
return
fi
fi
# 降级: 手动输入
read -p "Commit message: " msg
git commit -m "$msg"
}
工作流设计模式
模式1: 流水线模式
适用于: 顺序执行的任务链
# 部署流水线
function deploy() {
echo "1️⃣ Running tests..."
npm test || { echo "❌ Tests failed"; return 1; }
echo "2️⃣ Building..."
npm run build || { echo "❌ Build failed"; return 1; }
echo "3️⃣ Deploying..."
npm run deploy || { echo "❌ Deploy failed"; return 1; }
echo "✅ Deploy successful"
}
模式2: 并行执行模式
适用于: 独立的多任务
# 启动多个服务
function start_all() {
# 并行启动
npm run backend &
npm run frontend &
docker-compose up -d &
# 等待所有完成
wait
echo "✅ All services started"
}
模式3: 条件分支模式
适用于: 不同场景不同处理
function smart_test() {
# 检测改动范围
changed_files=$(git diff --name-only)
if echo "$changed_files" | grep -q "\.test\."; then
# 只运行改动的测试
npm test -- $changed_files
elif echo "$changed_files" | grep -q "src/"; then
# 运行相关测试
npm test -- --related
else
# 快速检查
npm run test:quick
fi
}
模式4: 重试模式
适用于: 可能失败但重试有用的操作
function retry() {
local max_attempts=3
local attempt=1
local command="$@"
while [ $attempt -le $max_attempts ]; do
echo "Attempt $attempt/$max_attempts: $command"
if $command; then
echo "✅ Success"
return 0
fi
echo "❌ Failed, retrying..."
attempt=$((attempt + 1))
sleep 2
done
echo "❌ Failed after $max_attempts attempts"
return 1
}
# 使用
retry npm install
retry curl https://api.example.com
模式5: 缓存模式
适用于: 昂贵的操作
function get_project_info() {
local cache_file="/tmp/project-info-$(pwd | md5).cache"
local cache_ttl=3600 # 1小时
# 检查缓存
if [ -f "$cache_file" ]; then
local age=$(($(date +%s) - $(stat -f %m "$cache_file")))
if [ $age -lt $cache_ttl ]; then
cat "$cache_file"
return
fi
fi
# 重新计算
local info=$(expensive_calculation)
echo "$info" | tee "$cache_file"
}
命名规范
脚本命名
✅ 好的命名:
- dev-start.sh (清晰的动词-名词)
- git-smart-commit.sh (带前缀分类)
- note-quick-add.sh (描述性)
❌ 不好的命名:
- script.sh (太泛泛)
- utils.sh (不具体)
- my_thing.sh (不清楚)
函数命名
# ✅ 动词开头,清晰表达意图
function start_dev_server() { }
function check_git_status() { }
function generate_report() { }
# ❌ 模糊不清
function do_stuff() { }
function helper() { }
function run() { }
变量命名
# ✅ 描述性,用大写表示常量
PROJECT_DIR="$HOME/Developer"
MAX_RETRIES=3
current_branch=$(git branch --show-current)
# ❌ 无意义的名字
d="$HOME/Developer"
x=3
tmp=$(git branch --show-current)
错误处理
1. 始终检查关键操作
# ❌ 不检查错误
cd "$PROJECT_DIR"
rm -rf node_modules
# ✅ 检查并处理
if [ ! -d "$PROJECT_DIR" ]; then
echo "❌ Project directory not found"
exit 1
fi
cd "$PROJECT_DIR" || exit 1
rm -rf node_modules
2. 提供有用的错误信息
# ❌ 错误信息不明确
echo "Error"
# ✅ 清晰的上下文
echo "❌ Failed to connect to database"
echo " Check if PostgreSQL is running: brew services list"
echo " Connection string: $DB_URL"
3. 使用trap清理资源
function cleanup() {
echo "🧹 Cleaning up..."
# 停止后台进程
kill $SERVER_PID 2>/dev/null
# 删除临时文件
rm -f /tmp/my-script-*
}
trap cleanup EXIT
# 你的脚本逻辑
npm run dev &
SERVER_PID=$!
性能优化
1. 避免不必要的操作
# ❌ 每次都检查
if [ -f "package.json" ]; then
npm install
fi
# ✅ 只在需要时安装
if [ -f "package.json" ] && [ ! -d "node_modules" ]; then
npm install
elif [ "package.json" -nt "node_modules" ]; then
npm install
fi
2. 并行化独立任务
# ❌ 串行执行 (慢)
lint_code
run_tests
build_project
# ✅ 并行执行 (快)
lint_code &
run_tests &
build_project &
wait
3. 使用合适的工具
# ❌ 慢
find . -name "*.js" -exec cat {} \; | wc -l
# ✅ 快
rg --files --type js | xargs wc -l
安全实践
1. 永不硬编码密钥
# ❌ 危险
API_KEY="sk-1234567890abcdef"
# ✅ 从环境变量读取
API_KEY="${API_KEY:-}"
if [ -z "$API_KEY" ]; then
echo "❌ API_KEY not set"
exit 1
fi
# 或从加密存储读取
API_KEY=$(security find-generic-password -s "my-api-key" -w)
2. 限制文件权限
# 创建敏感配置文件
touch ~/.config/secrets.env
chmod 600 ~/.config/secrets.env # 只有所有者可读写
3. 验证输入
function deploy() {
local env=$1
# 验证环境
if [[ ! "$env" =~ ^(dev|staging|production)$ ]]; then
echo "❌ Invalid environment: $env"
echo " Valid: dev, staging, production"
exit 1
fi
# 生产环境额外确认
if [ "$env" = "production" ]; then
read -p "⚠️ Deploy to PRODUCTION? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
echo "Cancelled"
exit 0
fi
fi
# 继续部署...
}
4. 审计日志
function log_action() {
local action=$1
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] $USER: $action" >> ~/.automation/audit.log
}
function sensitive_operation() {
log_action "Deploying to production"
# 执行操作...
}
可维护性
1. 文档化
#!/bin/bash
#
# 脚本名称: smart-deploy.sh
# 描述: 智能部署脚本,支持多环境
# 作者: Your Name
# 创建日期: 2025-01-01
# 最后修改: 2025-01-15
#
# 使用方法:
# ./smart-deploy.sh <environment> [options]
#
# 参数:
# environment 部署环境 (dev|staging|production)
# --skip-tests 跳过测试 (不推荐)
# --force 强制部署
#
# 示例:
# ./smart-deploy.sh staging
# ./smart-deploy.sh production --force
#
function deploy() {
# 函数文档
# 执行部署流程
# 参数: $1 - 环境名称
# 返回: 0 成功, 1 失败
...
}
2. 模块化
# 不要把所有代码放一个文件
# lib/utils.sh
function log() { echo "[$(date)] $*"; }
function error() { echo "❌ $*" >&2; }
# lib/git.sh
function check_git_clean() { ... }
function get_current_branch() { ... }
# main.sh
source lib/utils.sh
source lib/git.sh
function main() {
log "Starting..."
...
}
main "$@"
3. 版本控制
# 所有自动化脚本都应该在Git中管理
mkdir -p ~/.automation
cd ~/.automation
git init
# .gitignore
echo "*.log" >> .gitignore
echo "*.cache" >> .gitignore
echo "secrets.env" >> .gitignore
# 提交
git add .
git commit -m "Initial automation setup"
测试策略
1. 干运行模式
DRY_RUN=false
function execute() {
local cmd=$1
if [ "$DRY_RUN" = true ]; then
echo "[DRY RUN] $cmd"
else
eval "$cmd"
fi
}
# 使用
execute "rm -rf node_modules"
execute "npm install"
# 测试时: DRY_RUN=true ./script.sh
2. 单元测试函数
# test-utils.sh
function test_extract_project_name() {
local input="/home/user/projects/my-app"
local expected="my-app"
local result=$(extract_project_name "$input")
if [ "$result" = "$expected" ]; then
echo "✅ test_extract_project_name passed"
else
echo "❌ test_extract_project_name failed"
echo " Expected: $expected"
echo " Got: $result"
exit 1
fi
}
# 运行测试
test_extract_project_name
3. 集成测试
# integration-test.sh
function test_full_workflow() {
echo "Testing full deployment workflow..."
# 创建测试项目
mkdir -p /tmp/test-project
cd /tmp/test-project
git init
echo "test" > README.md
git add .
git commit -m "test"
# 执行工作流
if ../scripts/deploy.sh test; then
echo "✅ Integration test passed"
else
echo "❌ Integration test failed"
exit 1
fi
# 清理
cd -
rm -rf /tmp/test-project
}
test_full_workflow
常见陷阱和解决方案
陷阱1: 路径问题
# ❌ 问题: 相对路径在不同目录执行会出错
cd scripts
./deploy.sh
# ✅ 解决: 使用绝对路径
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
陷阱2: 空格问题
# ❌ 问题: 文件名有空格
for file in $(ls); do
echo $file # 空格会被拆分
done
# ✅ 解决: 正确引用
while IFS= read -r file; do
echo "$file"
done < <(ls)
# 或者
for file in *; do
echo "$file"
done
陷阱3: 子shell问题
# ❌ 问题: 变量在子shell中修改不生效
cat file.txt | while read line; do
count=$((count + 1))
done
echo $count # 还是0
# ✅ 解决: 避免管道
while read line; do
count=$((count + 1))
done < file.txt
echo $count # 正确
陷阱4: 过度自动化
症状:
- 配置复杂度超过任务本身
- 花更多时间维护自动化而不是使用
- 团队其他人看不懂
解决:
- 保持简单
- 文档化
- 渐进增强
- 定期审查:这个自动化还有用吗?
检查清单
脚本发布前
- 添加shebang (#!/bin/bash)
- 添加注释和文档
- 检查错误处理
- 测试边界情况
- 设置正确的文件权限
- 无硬编码的密钥
- 有使用示例
工作流设计前
- 真的需要自动化吗?
- 频率够高吗?
- 有降级方案吗?
- 错误时怎么办?
- 如何监控?
- 如何测试?
- 团队能用吗?
定期审查 (每月)
- 哪些自动化最有用?
- 哪些从不使用?
- 有新的痛点吗?
- 可以合并简化吗?
- 文档是最新的吗?
- 有安全问题吗?
记住: 最好的代码是不写的代码。在自动化之前,先问"这是必要的吗?"