如何编写批量替换文件名脚本

wen 实用脚本 2

本文目录导读:

如何编写批量替换文件名脚本

  1. Python 脚本(最灵活)
  2. Bash/Shell 脚本(Linux/Mac)
  3. Windows Batch 脚本
  4. Node.js 脚本
  5. 使用建议
  6. 快速使用示例

我来介绍几种批量替换文件名的脚本方法,涵盖不同场景和需求。

Python 脚本(最灵活)

基础版 - 简单替换

import os
from pathlib import Path
def batch_rename(directory, old_str, new_str):
    """
    批量替换文件名中的指定字符串
    Args:
        directory: 目标目录
        old_str: 要替换的旧字符串
        new_str: 替换成的新字符串
    """
    dir_path = Path(directory)
    for file_path in dir_path.iterdir():
        if file_path.is_file():
            # 生成新文件名
            new_name = file_path.name.replace(old_str, new_str)
            # 如果有变化则重命名
            if new_name != file_path.name:
                new_path = file_path.with_name(new_name)
                file_path.rename(new_path)
                print(f"重命名: {file_path.name} → {new_name}")
# 使用示例
batch_rename("./my_files", "2023", "2024")

进阶版 - 使用正则表达式

import os
import re
from pathlib import Path
def regex_rename(directory, pattern, replacement, recursive=False):
    """
    使用正则表达式批量替换文件名
    Args:
        directory: 目标目录
        pattern: 正则表达式模式
        replacement: 替换字符串(支持反向引用如 \1)
        recursive: 是否递归子目录
    """
    dir_path = Path(directory)
    files = dir_path.rglob("*") if recursive else dir_path.iterdir()
    for file_path in files:
        if file_path.is_file():
            try:
                # 使用正则替换
                new_name = re.sub(pattern, replacement, file_path.name)
                if new_name != file_path.name:
                    new_path = file_path.with_name(new_name)
                    file_path.rename(new_path)
                    print(f"重命名: {file_path.name} → {new_name}")
            except Exception as e:
                print(f"处理 {file_path.name} 出错: {e}")
# 使用示例
# 将文件名中的数字改为下划线格式
regex_rename("./files", r"(\d{4})-(\d{2})-(\d{2})", r"\1年\2月\3日", recursive=True)

高级版 - 添加序号和格式处理

import os
from pathlib import Path
class BatchRenamer:
    def __init__(self, directory):
        self.directory = Path(directory)
    def add_prefix(self, prefix, ext_filter=None):
        """给文件名添加前缀"""
        for file in self._get_files(ext_filter):
            new_name = f"{prefix}{file.name}"
            self._rename(file, new_name)
    def add_suffix(self, suffix, ext_filter=None):
        """给文件名添加后缀(在扩展名之前)"""
        for file in self._get_files(ext_filter):
            stem = file.stem
            new_name = f"{stem}{suffix}{file.suffix}"
            self._rename(file, new_name)
    def add_sequence(self, start=1, digits=3, ext_filter=None):
        """给文件名添加序号"""
        for i, file in enumerate(self._get_files(ext_filter), start):
            seq = str(i).zfill(digits)
            new_name = f"{seq}_{file.name}"
            self._rename(file, new_name)
    def change_extension(self, new_ext, ext_filter=None):
        """修改文件扩展名"""
        for file in self._get_files(ext_filter):
            new_name = f"{file.stem}.{new_ext}"
            self._rename(file, new_name)
    def _get_files(self, ext_filter):
        """获取符合条件的文件列表"""
        files = [f for f in self.directory.iterdir() if f.is_file()]
        if ext_filter:
            if isinstance(ext_filter, str):
                ext_filter = [ext_filter]
            files = [f for f in files if f.suffix.lstrip('.') in ext_filter]
        return files
    def _rename(self, file, new_name):
        """执行重命名操作"""
        if file.name != new_name:
            new_path = file.with_name(new_name)
            if new_path.exists():
                print(f"跳过 {file.name}: 目标文件已存在")
            else:
                file.rename(new_path)
                print(f"重命名: {file.name} → {new_name}")
# 使用示例
renamer = BatchRenamer("./my_files")
# 添加前缀
renamer.add_prefix("2024_")
# 添加序号(只处理txt文件)
renamer.add_sequence(start=1, digits=4, ext_filter="txt")
# 修改扩展名
renamer.change_extension("bak", ext_filter=["txt", "doc"])

Bash/Shell 脚本(Linux/Mac)

基础版

#!/bin/bash
# 批量替换文件名
replace_in_names() {
    local directory="$1"
    local old_str="$2"
    local new_str="$3"
    for file in "$directory"/*; do
        if [ -f "$file" ]; then
            filename=$(basename "$file")
            new_filename="${filename//$old_str/$new_str}"
            if [ "$filename" != "$new_filename" ]; then
                mv "$file" "$directory/$new_filename"
                echo "重命名: $filename → $new_filename"
            fi
        fi
    done
}
# 使用示例
replace_in_names "./files" "old" "new"

高级版 - 带参数和错误处理

#!/bin/bash
usage() {
    echo "用法: $0 [-d 目录] [-o 旧字符串] [-n 新字符串] [-s 序号开始]"
    echo "示例: $0 -d ./files -o old -n new"
    echo "      $0 -d ./files -s 1"
    exit 1
}
# 解析参数
while getopts "d:o:n:s:" opt; do
    case $opt in
        d) DIRECTORY="$OPTARG" ;;
        o) OLD_STR="$OPTARG" ;;
        n) NEW_STR="$OPTARG" ;;
        s) SEQUENCE="$OPTARG" ;;
        *) usage ;;
    esac
done
# 检查参数
if [ -z "$DIRECTORY" ]; then
    echo "错误: 请指定目录"
    usage
fi
if [ ! -d "$DIRECTORY" ]; then
    echo "错误: 目录不存在"
    exit 1
fi
# 执行重命名
if [ -n "$OLD_STR" ] && [ -n "$NEW_STR" ]; then
    # 执行替换
    for file in "$DIRECTORY"/*; do
        if [ -f "$file" ]; then
            filename=$(basename "$file")
            new_filename="${filename//$OLD_STR/$NEW_STR}"
            if [ "$filename" != "$new_filename" ]; then
                if [ -f "$DIRECTORY/$new_filename" ]; then
                    echo "警告: 目标文件存在,跳过 $filename"
                else
                    mv "$file" "$DIRECTORY/$new_filename"
                    echo "重命名: $filename → $new_filename"
                fi
            fi
        fi
    done
elif [ -n "$SEQUENCE" ]; then
    # 添加序号
    count=$SEQUENCE
    for file in "$DIRECTORY"/*; do
        if [ -f "$file" ]; then
            filename=$(basename "$file")
            # 使用3位数字补零
            seq=$(printf "%03d" $count)
            new_filename="${seq}_${filename}"
            mv "$file" "$DIRECTORY/$new_filename"
            echo "重命名: $filename → $new_filename"
            ((count++))
        fi
    done
else
    usage
fi
echo "完成!"

Windows Batch 脚本

Windows批处理

@echo off
setlocal enabledelayedexpansion
echo ==================================
echo    批量文件名替换工具
echo ==================================
set /p directory=请输入目录路径: 
set /p old_str=请输入要替换的字符: 
set /p new_str=请输入新字符: 
if not exist "%directory%" (
    echo 目录不存在!
    pause
    exit /b
)
cd /d "%directory%"
for %%f in (*.*) do (
    set "filename=%%~nf"
    set "extension=%%~xf"
    rem 替换文件名
    set "newfilename=!filename:%old_str%=%new_str%!"
    rem 检查是否有变化
    if not "!filename!"=="!newfilename!" (
        ren "%%f" "!newfilename!!extension!"
        echo 重命名: %%f → !newfilename!!extension!
    )
)
echo.
echo 操作完成!
pause

PowerShell 脚本(Windows)

# PowerShell 批量重命名脚本
param(
    [string]$Path = ".",
    [string]$OldString,
    [string]$NewString,
    [switch]$Recursive,
    [switch]$WhatIf  # 预览模式
)
function Rename-Files {
    $files = if ($Recursive) {
        Get-ChildItem -Path $Path -File -Recurse
    } else {
        Get-ChildItem -Path $Path -File
    }
    foreach ($file in $files) {
        $newName = $file.Name.Replace($OldString, $NewString)
        if ($file.Name -ne $newName) {
            $newPath = Join-Path $file.DirectoryName $newName
            if ($WhatIf) {
                Write-Host "预览: $($file.Name) → $newName" -ForegroundColor Yellow
            } else {
                try {
                    Move-Item -Path $file.FullName -Destination $newPath -ErrorAction Stop
                    Write-Host "已重命名: $($file.Name) → $newName" -ForegroundColor Green
                } catch {
                    Write-Warning "重命名失败: $($file.Name) - $_"
                }
            }
        }
    }
}
# 使用预检查
Write-Host "开始处理..." -ForegroundColor Cyan
Rename-Files
if (-not $WhatIf) {
    Write-Host "完成!" -ForegroundColor Green
}

Node.js 脚本

#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const readline = require('readline');
// 创建命令行交互
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});
function batchRename(directory, oldStr, newStr, options = {}) {
    const files = fs.readdirSync(directory);
    files.forEach((filename) => {
        const filePath = path.join(directory, filename);
        // 检查是否为文件
        if (fs.statSync(filePath).isFile()) {
            // 检查扩展名过滤
            if (options.exts && !options.exts.some(ext => filename.endsWith(ext))) {
                return;
            }
            // 替换文件名
            const newFilename = filename.replace(oldStr, newStr);
            // 执行重命名
            if (filename !== newFilename) {
                const newPath = path.join(directory, newFilename);
                if (fs.existsSync(newPath)) {
                    console.log(`跳过 ${filename}: 目标文件已存在`);
                } else {
                    fs.renameSync(filePath, newPath);
                    console.log(`重命名: ${filename} → ${newFilename}`);
                }
            }
        }
    });
}
// 命令行交互
rl.question('请输入目录路径: ', (directory) => {
    rl.question('请输入要替换的字符串: ', (oldStr) => {
        rl.question('请输入新字符串: ', (newStr) => {
            rl.question('是否限制扩展名? (y/n): ', (answer) => {
                if (answer.toLowerCase() === 'y') {
                    rl.question('请输入扩展名(用逗号分隔): ', (extsInput) => {
                        const exts = extsInput.split(',').map(e => e.trim());
                        batchRename(directory, oldStr, newStr, { exts });
                        console.log('完成!');
                        rl.close();
                    });
                } else {
                    batchRename(directory, oldStr, newStr);
                    console.log('完成!');
                    rl.close();
                }
            });
        });
    });
});

使用建议

  1. 先备份:批量操作前务必备份重要文件
  2. 预览功能:尽量使用带预览功能的脚本(如 -WhatIf 参数)
  3. 测试环境:先用测试目录验证脚本逻辑
  4. 异常处理:脚本应包含错误处理和冲突检查
  5. 日志记录:保存重命名记录,便于追踪和撤销

快速使用示例

Python 一行命令示例:

# 在命令行直接运行
python -c "import os; [os.rename(f, f.replace('old', 'new')) for f in os.listdir('.') if 'old' in f]"

Bash 一行命令示例:

# 替换当前目录下所有文件的old为new
for f in *; do [ -f "$f" ] && mv "$f" "${f//old/new}"; done

选择哪种脚本取决于你的:

  • 操作系统
  • 文件量大小
  • 操作复杂度
  • 是否需要交互界面

建议先从简单的版本开始测试,确认无误后再批量执行。

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