#!/bin/bash # 安全文件编辑脚本 # 基于2026-03-13文件编辑失败的经验教训 set -e # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 显示帮助信息 show_help() { echo "🔧 安全文件编辑脚本" echo "======================" echo "用法: $0 <文件路径> <旧文本> <新文本>" echo "" echo "选项:" echo " -h, --help 显示帮助信息" echo " -v, --verbose 详细模式" echo " -b, --backup 保留备份文件(默认编辑成功后删除)" echo " -f, --force 强制编辑(不检查匹配次数)" echo "" echo "示例:" echo " $0 config.yaml 'port: 8080' 'port: 9090'" echo " $0 --verbose README.md '旧版本' '新版本'" echo "" echo "安全特性:" echo " • 自动备份原文件" echo " • 验证文本匹配" echo " • 失败时自动恢复" echo " • 编辑日志记录" } # 初始化变量 VERBOSE=0 KEEP_BACKUP=0 FORCE=0 FILE="" OLD_TEXT="" NEW_TEXT="" # 解析参数 while [[ $# -gt 0 ]]; do case $1 in -h|--help) show_help exit 0 ;; -v|--verbose) VERBOSE=1 shift ;; -b|--backup) KEEP_BACKUP=1 shift ;; -f|--force) FORCE=1 shift ;; *) if [ -z "$FILE" ]; then FILE="$1" elif [ -z "$OLD_TEXT" ]; then OLD_TEXT="$1" elif [ -z "$NEW_TEXT" ]; then NEW_TEXT="$1" else echo -e "${RED}错误:参数过多${NC}" show_help exit 1 fi shift ;; esac done # 检查必要参数 if [ -z "$FILE" ] || [ -z "$OLD_TEXT" ] || [ -z "$NEW_TEXT" ]; then echo -e "${RED}错误:缺少必要参数${NC}" show_help exit 1 fi # 检查文件是否存在 if [ ! -f "$FILE" ]; then echo -e "${RED}错误:文件不存在: $FILE${NC}" exit 1 fi # 详细模式输出 log() { if [ $VERBOSE -eq 1 ]; then echo -e "${BLUE}[INFO]${NC} $1" fi } error() { echo -e "${RED}[ERROR]${NC} $1" } success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } # 主函数 main() { echo "🔧 开始安全文件编辑" echo "======================" echo "文件: $FILE" echo "旧文本: \"$OLD_TEXT\"" echo "新文本: \"$NEW_TEXT\"" echo "" # 步骤1:备份原文件 BACKUP_FILE="${FILE}.backup.$(date +%Y%m%d_%H%M%S)" log "创建备份: $BACKUP_FILE" cp "$FILE" "$BACKUP_FILE" if [ $? -ne 0 ]; then error "备份失败" exit 1 fi # 步骤2:检查文件权限 PERMISSIONS=$(stat -f "%Sp" "$FILE") log "文件权限: $PERMISSIONS" # 步骤3:验证文本匹配 log "验证文本匹配..." # 检查匹配次数 MATCH_COUNT=$(grep -c "$OLD_TEXT" "$FILE") log "找到 $MATCH_COUNT 处匹配" if [ $MATCH_COUNT -eq 0 ]; then error "未找到匹配文本" echo "建议:" echo " 1. 检查文本是否完全匹配(包括空格和换行符)" echo " 2. 使用 cat -A 查看文件特殊字符" echo " 3. 考虑使用 write 工具重新创建文件" if [ $FORCE -eq 0 ]; then # 恢复备份 log "恢复备份文件" cp "$BACKUP_FILE" "$FILE" exit 1 else warning "强制模式:继续编辑" fi elif [ $MATCH_COUNT -gt 1 ] && [ $FORCE -eq 0 ]; then warning "找到 $MATCH_COUNT 处匹配,可能不精确" echo "匹配位置:" grep -n "$OLD_TEXT" "$FILE" echo "" echo "建议:" echo " 1. 使用更精确的匹配文本" echo " 2. 使用 -f 参数强制编辑" echo " 3. 或手动编辑文件" # 恢复备份 log "恢复备份文件" cp "$BACKUP_FILE" "$FILE" exit 1 fi # 步骤4:显示匹配上下文 if [ $VERBOSE -eq 1 ]; then echo "匹配上下文:" grep -A2 -B2 "$OLD_TEXT" "$FILE" | cat -A echo "" fi # 步骤5:执行编辑 log "执行编辑操作..." edit "$FILE" "$OLD_TEXT" "$NEW_TEXT" if [ $? -ne 0 ]; then error "编辑失败" log "恢复备份文件" cp "$BACKUP_FILE" "$FILE" exit 1 fi # 步骤6:验证编辑结果 log "验证编辑结果..." # 检查新文本是否存在 NEW_COUNT=$(grep -c "$NEW_TEXT" "$FILE") if [ $NEW_COUNT -eq 0 ]; then error "新文本未找到,编辑可能失败" log "恢复备份文件" cp "$BACKUP_FILE" "$FILE" exit 1 fi # 检查旧文本是否还存在 OLD_COUNT=$(grep -c "$OLD_TEXT" "$FILE") if [ $OLD_COUNT -gt 0 ]; then warning "仍有 $OLD_COUNT 处旧文本存在" fi # 步骤7:文件完整性检查 log "检查文件完整性..." # 检查文件大小 ORIG_SIZE=$(stat -f%z "$BACKUP_FILE") NEW_SIZE=$(stat -f%z "$FILE") log "原始大小: $ORIG_SIZE 字节" log "新大小: $NEW_SIZE 字节" if [ $NEW_SIZE -eq 0 ]; then error "文件大小为0,编辑可能损坏了文件" log "恢复备份文件" cp "$BACKUP_FILE" "$FILE" exit 1 fi # 步骤8:清理和记录 if [ $KEEP_BACKUP -eq 0 ]; then log "删除备份文件" rm "$BACKUP_FILE" else log "保留备份文件: $BACKUP_FILE" fi # 记录编辑日志 LOG_FILE="$HOME/.openclaw/workspace/managed-systems/logs/edit-log.md" mkdir -p "$(dirname "$LOG_FILE")" echo "## $(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG_FILE" echo "- **文件**: $FILE" >> "$LOG_FILE" echo "- **操作**: 替换文本" >> "$LOG_FILE" echo "- **匹配数**: $MATCH_COUNT" >> "$LOG_FILE" echo "- **结果**: 成功" >> "$LOG_FILE" echo "" >> "$LOG_FILE" # 步骤9:完成 success "编辑成功完成" echo "" echo "📊 编辑统计:" echo " • 匹配位置: $MATCH_COUNT 处" echo " • 新文本出现: $NEW_COUNT 次" echo " • 文件大小变化: $ORIG_SIZE → $NEW_SIZE 字节" if [ $KEEP_BACKUP -eq 1 ]; then echo " • 备份文件: $BACKUP_FILE" fi echo "" echo "✅ 安全编辑流程完成" } # 运行主函数 main "$@"