262 lines
6.8 KiB
Bash
262 lines
6.8 KiB
Bash
#!/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 "$@" |