如何编写限定代码替换目录范围脚本

wen 实用脚本 25

本文目录导读:

如何编写限定代码替换目录范围脚本

  1. Python版本(最灵活)
  2. Shell脚本版本(Linux/Mac)
  3. PowerShell版本(Windows)
  4. 使用示例
  5. 安全建议

我来为您编写一个限定目录范围的代码替换脚本,提供几种常见实现方式:

Python版本(最灵活)

#!/usr/bin/env python3
"""
限定目录范围的代码替换脚本
功能:在指定目录范围内查找并替换文本
"""
import os
import re
import argparse
from pathlib import Path
class DirectoryLimitedReplacer:
    def __init__(self, base_dir, include_extensions=None, exclude_dirs=None):
        """
        初始化替换器
        Args:
            base_dir: 基础目录
            include_extensions: 要处理的文件扩展名列表,如 ['.py', '.js']
            exclude_dirs: 要排除的目录名列表
        """
        self.base_dir = Path(base_dir)
        self.include_extensions = include_extensions or ['.py', '.js', '.html', '.css']
        self.exclude_dirs = exclude_dirs or ['.git', '__pycache__', 'node_modules', 'venv']
        self.changed_files = []
    def should_process_file(self, file_path):
        """判断是否应该处理该文件"""
        # 检查扩展名
        if file_path.suffix not in self.include_extensions:
            return False
        # 检查是否在排除目录中
        for part in file_path.parts:
            if part in self.exclude_dirs:
                return False
        return True
    def replace_in_file(self, file_path, old_text, new_text, use_regex=False):
        """在单个文件中执行替换"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            if use_regex:
                new_content = re.sub(old_text, new_text, content)
            else:
                new_content = content.replace(old_text, new_text)
            if new_content != content:
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(new_content)
                self.changed_files.append(str(file_path))
                return True
            return False
        except Exception as e:
            print(f"Error processing {file_path}: {e}")
            return False
    def replace_all(self, old_text, new_text, use_regex=False):
        """在范围内所有文件中执行替换"""
        for file_path in self.base_dir.rglob('*'):
            if file_path.is_file() and self.should_process_file(file_path):
                self.replace_in_file(file_path, old_text, new_text, use_regex)
        return self.changed_files
def main():
    parser = argparse.ArgumentParser(description='限定目录范围的代码替换工具')
    parser.add_argument('old_text', help='要替换的文本')
    parser.add_argument('new_text', help='替换后的文本')
    parser.add_argument('--dir', '-d', default='.', help='目标目录(默认为当前目录)')
    parser.add_argument('--extensions', '-e', nargs='+', 
                       default=['.py', '.js', '.html', '.css', '.txt'],
                       help='要处理的文件扩展名')
    parser.add_argument('--exclude', '-x', nargs='+',
                       default=['.git', '__pycache__', 'node_modules'],
                       help='要排除的目录')
    parser.add_argument('--regex', '-r', action='store_true',
                       help='使用正则表达式匹配')
    parser.add_argument('--dry-run', action='store_true',
                       help='仅显示将要修改的文件,不实际修改')
    args = parser.parse_args()
    replacer = DirectoryLimitedReplacer(
        args.dir,
        include_extensions=args.extensions,
        exclude_dirs=args.exclude
    )
    if args.dry_run:
        print("【模拟运行模式】将修改以下文件:")
        for file_path in Path(args.dir).rglob('*'):
            if file_path.is_file() and replacer.should_process_file(file_path):
                with open(file_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                if args.regex:
                    if re.search(args.old_text, content):
                        print(f"  {file_path}")
                else:
                    if args.old_text in content:
                        print(f"  {file_path}")
    else:
        changed = replacer.replace_all(args.old_text, args.new_text, args.regex)
        print(f"修改完成,共修改 {len(changed)} 个文件:")
        for f in changed:
            print(f"  {f}")
if __name__ == '__main__':
    main()

Shell脚本版本(Linux/Mac)

#!/bin/bash
# filename: limited_replace.sh
# 限定目录范围的代码替换脚本
# 使用方式: ./limited_replace.sh "旧文本" "新文本" [目录] [扩展名]
OLD_TEXT="${1}"
NEW_TEXT="${2}"
TARGET_DIR="${3:-.}"
EXTENSIONS="${4:-py,js,html,css,txt}"
# 排除的目录
EXCLUDE_DIRS=(".git" "__pycache__" "node_modules" "venv")
# 颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
echo "开始替换操作..."
echo "目标目录: $TARGET_DIR"
echo "替换文本: '$OLD_TEXT' -> '$NEW_TEXT'"
echo "文件类型: $EXTENSIONS"
# 构建find命令的排除参数
EXCLUDE_ARGS=""
for dir in "${EXCLUDE_DIRS[@]}"; do
    EXCLUDE_ARGS="$EXCLUDE_ARGS -not -path '*/$dir/*'"
done
# 将扩展名转换为find格式
IFS=',' read -ra EXT_ARRAY <<< "$EXTENSIONS"
FIND_EXT_ARGS=""
for ext in "${EXT_ARRAY[@]}"; do
    if [ -z "$FIND_EXT_ARGS" ]; then
        FIND_EXT_ARGS="-name '*.$ext'"
    else
        FIND_EXT_ARGS="$FIND_EXT_ARGS -o -name '*.$ext'"
    fi
done
# 查找并替换
find "$TARGET_DIR" -type f $FIND_EXT_ARGS $EXCLUDE_ARGS | while read -r file; do
    if grep -q "$OLD_TEXT" "$file" 2>/dev/null; then
        echo -e "${GREEN}修改:${NC} $file"
        # MacOS使用sed -i '',Linux使用sed -i
        if [[ "$OSTYPE" == "darwin"* ]]; then
            sed -i '' "s|$OLD_TEXT|$NEW_TEXT|g" "$file"
        else
            sed -i "s|$OLD_TEXT|$NEW_TEXT|g" "$file"
        fi
    fi
done
echo -e "${GREEN}替换完成!${NC}"

PowerShell版本(Windows)

# filename: LimitedReplace.ps1
# 限定目录范围的代码替换脚本
param(
    [Parameter(Mandatory=$true)]
    [string]$OldText,
    [Parameter(Mandatory=$true)]
    [string]$NewText,
    [string]$TargetDir = ".",
    [string[]]$Extensions = @("*.py", "*.js", "*.html", "*.css", "*.txt"),
    [string[]]$ExcludeDirs = @(".git", "__pycache__", "node_modules", "venv"),
    [switch]$DryRun,
    [switch]$UseRegex
)
# 获取所有符合条件的文件
Write-Host "正在扫描文件..." -ForegroundColor Cyan
$files = Get-ChildItem -Path $TargetDir -Recurse -File -Include $Extensions |
         Where-Object {
             $exclude = $false
             foreach ($dir in $ExcludeDirs) {
                 if ($_.FullName -match [regex]::Escape($dir)) {
                     $exclude = $true
                     break
                 }
             }
             -not $exclude
         }
$changedFiles = @()
foreach ($file in $files) {
    try {
        $content = Get-Content -Path $file.FullName -Raw
        if ($UseRegex) {
            $newContent = $content -replace $OldText, $NewText
        } else {
            $newContent = $content -replace [regex]::Escape($OldText), $NewText
        }
        if ($newContent -ne $content) {
            if (-not $DryRun) {
                Set-Content -Path $file.FullName -Value $newContent -NoNewline
            }
            $changedFiles += $file.FullName
            Write-Host "$(if ($DryRun) {'[模拟]'} else {'[修改]'}) $($file.FullName)" -ForegroundColor Green
        }
    }
    catch {
        Write-Warning "处理文件 $($file.FullName) 时出错: $_"
    }
}
Write-Host "`n操作完成!" -ForegroundColor Cyan
Write-Host "共处理文件: $($files.Count) 个"
Write-Host "实际修改: $($changedFiles.Count) 个"
if ($changedFiles.Count -gt 0) {
    Write-Host "`n修改的文件列表:" -ForegroundColor Yellow
    $changedFiles | ForEach-Object { Write-Host "  $_" }
}

使用示例

Python版本

# 基本使用
python replace_script.py "旧代码" "新代码"
# 指定目录和文件类型
python replace_script.py "console.log" "logger.info" -d ./src -e .js .ts
# 使用正则表达式
python replace_script.py "var\s+(\w+)" "let $1" -r
# 模拟运行(不实际修改)
python replace_script.py "旧文本" "新文本" --dry-run

Shell版本

# 添加执行权限
chmod +x limited_replace.sh
# 在当前目录替换
./limited_replace.sh "old_text" "new_text"
# 在指定目录替换JS文件
./limited_replace.sh "var " "let " ./src js
# 使用不同的分隔符避免冲突
./limited_replace.sh "path/to/old" "path/to/new" ./config

PowerShell版本

# 设置执行策略(如果需要)
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
# 基本使用
.\LimitedReplace.ps1 -OldText "旧代码" -NewText "新代码"
# 高级使用
.\LimitedReplace.ps1 -OldText "function\(" -NewText "async function(" `
                     -TargetDir ./src -Extensions *.js,*.ts `
                     -ExcludeDirs node_modules,dist -UseRegex
# 模拟运行
.\LimitedReplace.ps1 -OldText "旧文本" -NewText "新文本" -DryRun

安全建议

  1. 始终先备份:在执行替换前备份重要文件
  2. 使用模拟模式:先用 --dry-run-WhatIf 查看将要修改的文件
  3. 限制搜索范围:精确指定目录和文件类型,避免意外修改
  4. 使用版本控制:在Git仓库中使用前,确保工作区干净
  5. 测试正则表达式:使用 -r 正则模式时,先用小范围测试

选择哪个版本取决于您的操作系统和使用场景:

  • Python版本:跨平台,功能最完整
  • Shell版本:Linux/Mac环境最方便
  • PowerShell版本:Windows环境原生支持

抱歉,评论功能暂时关闭!