news 2026/9/7 13:14:10

批量删除文件夹名关键字的三种脚本方案:批处理、PowerShell与Python实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
批量删除文件夹名关键字的三种脚本方案:批处理、PowerShell与Python实践

在整理电脑文件时,最耗时的操作之一就是把一批文件夹名里的相同关键字去掉。比如课程目录统一带着“【完结】”、项目备份目录带着“_final”、导出文件目录带着“来源-”前缀。手动右键重命名,文件夹少时还行;一旦文件夹数量超过几十个,手动处理既慢又容易漏改,还会因为名称大小写、前后缀位置不同而反复核对。更现实的情况是,你并不想删除整个文件夹,只想清理命名中的干扰信息,让目录看起来更整齐,或者让文件夹名能被其它自动化脚本正确识别。这里说的“关键字”,是指文件夹名称中重复出现的文本片段,和编程语言里的保留字不是一回事。本文提供批处理、PowerShell 和 Python 三种批量删除文件夹名关键字的实现方式,并重点说明执行前如何备份、执行后如何验证,以及遇到权限、编码和重名冲突时如何排查。

1. 先弄清楚“关键字删除”到底删的是什么

1.1 这里的“关键字”是文件夹名中的文本片段

在文件整理场景中,“关键字”指的不是数据库字段、也不是编程语法里的keyword,而是文件夹名称中出现频率较高的字符串。例如:

D:\downloads ├─ 课程A【完结】 ├─ 课程B【完结】 ├─ 复习笔记【完结】2024 ├─ 项目源代码【完结】v2 └─ 普通文件夹

如果目标是把“【完结】”从所有文件夹名里去掉,转换结果应该是:

D:\downloads ├─ 课程A ├─ 课程B ├─ 复习笔记2024 ├─ 项目源代码v2 └─ 普通文件夹

这里只做目录名替换,不会删除目录内容,也不会移动文件。注意“普通文件夹”没有关键字,应该保持不变。脚本必须能自动判断“名称是否包含关键字”以及“替换后的新名称是否和旧名称相同”。

1.2 批量删除其实包含三个动作:识别、替换、校验

把一次批量重命名拆开看,步骤非常固定:

  1. 遍历目标目录下所有文件夹。
  2. 对每个文件夹名执行字符串替换,去掉指定关键字。
  3. 检查新名称是否为空、是否与已有文件夹冲突,然后执行重命名。

真正的难点不在替换本身,而在边界情况。新名称为空怎么办。新名称已经存在怎么办。权限不足怎么办。脚本执行到一半失败怎么办。这些边界情况和生产环境遇到的真实问题关系更大。

1.3 批处理、PowerShell、Python 三套工具怎么选

三种方案各有适用场景,做一个简单的对比:

方案支持系统安装依赖试运行能力正则能力主要风险
批处理Windows无需安装手动模拟不支持特殊字符处理繁琐、延迟变量易踩坑
PowerShellWindows系统自带-WhatIf或 dry-run 变量支持执行策略、正则转义
PythonWindows / Linux / macOS需安装 Python自带 dry-run 参数支持环境依赖、编码问题

批量处理少量目录用批处理足够。处理规则简单但文件夹名包含括号、点号、空格等特殊字符时,建议用 Python 或 PowerShell。需要做正则匹配、需要递归子目录、需要输出结构化日志时,Python 更合适。

2. 动手前先完成备份、测试目录和运行环境准备

2.1 不要直接在生产目录里跑脚本

批量重命名一旦写错替换规则,可能把一批文件夹名改得面目全非。比如关键字写得太短,把course_final_v1里的_删掉,结果变成coursefinalv1。这类错误靠事后手工恢复非常痛苦。

最稳妥的做法是操作前先备份目录结构。Windows 下可以用 robocopy 保留目录结构:

robocopy D:\rename_test D:\rename_test_backup /E /COPY:DAT /R:2 /W:2

如果目录特别大,至少拷贝一份文件夹名清单,作为回滚依据:

Get-ChildItem -Path D:\rename_test -Directory | Select-Object -ExpandProperty Name | Sort-Object | Out-File D:\before.txt -Encoding UTF8

2.2 建一个最小测试目录

脚本第一次执行前,先用一个专门测试目录验证规则。建议目录结构这样放:

D:\rename_test ├─ 课程A【完结】 ├─ 课程B【完结】 ├─ 学习资料【完结】2024 ├─ 项目源代码【完结】v2 └─ 普通文件夹

测试目录里至少包含四类情况:名称中间包含关键字、名称开头或结尾包含关键字、名称不包含关键字、以及关键字删除后可能为空的极端情况。用这个小目录跑通脚本,再处理真实目录。

2.3 确认运行环境

批处理不需要额外环境,双击.bat文件或进入命令行执行即可。PowerShell 需要确认系统版本,Windows 10 以上一般自带 PowerShell 5.1,新版也可以安装 PowerShell 7。Python 方案需要先确认本机是否已安装:

python --version

如果提示找不到命令,需要先安装 Python 并勾选“Add Python to PATH”。不同系统之间 Python 脚本行为基本一致,这也是跨平台方案的优势。

3. Windows 下用批处理批量删除文件夹名关键字

3.1 完整批处理脚本

批处理适合在 Windows 环境中快速完成简单替换。下面脚本删除D:\rename_test下所有文件夹名中的“【完结】”:

@echo off setlocal enabledelayedexpansion set "keyword=【完结】" set "base=D:\rename_test" for /d %%i in ("%base%\*") do ( set "name=%%~nxi" set "new=!name:%keyword%=!" if "!new!"=="" ( echo [SKIP] 新名称为空, skip "%%i" ) else if not "!name!"=="!new!" ( if not exist "%base%\!new!" ( ren "%%i" "!new!" echo [OK] "%%i" -^> "!new!" ) else ( echo [SKIP] "!new!" already exists, skip "%%i" ) ) ) echo. echo 批量重命名完成。 pause

保存为rename_folder.bat,按目标目录修改keywordbase后运行。

3.2 批处理脚本关键点说明

setlocal enabledelayedexpansion这行最容易忽略。批处理中%var%在括号代码块被解析时只展开一次,循环内的变量更新值无法直接通过%xxx%读取。必须用!xxx!这种延迟变量写法,脚本才能正确处理每次循环的不同值。

for /d %%i in ("%base%\*")表示只遍历目录文件,不包含普通文件。for /d是目录遍历,%%i得到的是完整路径。要通过%%~nxi取出最后一级名称。

set "new=!name:%keyword%=!"是字符串替换语法,含义是把name中出现的%keyword%替换为空。这里的%keyword%在解析时已经展开,所以关键字本身即使包含中文字符,只要文件保存编码和命令提示符代码页一致,就能正常匹配。

脚本里加了两个保护条件:

  • new为空时跳过,避免把整个文件夹改成一个空名称。
  • 新名称已存在时跳过,避免覆盖同名目录。

3.3 批处理方案的两个明显局限

第一个局限是特殊字符。如果文件夹名包含!,在某些版本的命令提示符下会被延迟变量解析打断。如果关键字本身包含%&等符号,批处理替换会变得不可控。遇到这类名称,优先选择 PowerShell 或 Python。

第二个局限是编码。脚本文件保存为 UTF-8 时,在中文 Windows 命令提示符中可能出现乱码。可以先在脚本开头执行chcp 65001 >nul切换代码页,但仍要避免在不同语言系统之间直接复制脚本。如果只是自己电脑上用,保持脚本和系统代码页一致即可。

4. PowerShell 脚本实现更灵活的关键字删除

4.1 基础版:遍历目录并删除关键字

PowerShell 的优势在于对象化操作和内置日志能力。基础版脚本如下:

$keyword = "【完结】" $base = "D:\rename_test" Get-ChildItem -Path $base -Directory | ForEach-Object { $oldName = $_.Name $newName = $oldName.Replace($keyword, "") if ($newName -eq $oldName) { return } if ([string]::IsNullOrWhiteSpace($newName)) { Write-Warning "新名称为空,跳过: $oldName" return } $targetPath = Join-Path -Path $_.Parent.FullName -ChildPath $newName if (Test-Path -Path $targetPath) { Write-Warning "目标已存在,跳过: $oldName -> $newName" return } Rename-Item -Path $_.FullName -NewName $newName Write-Host "[OK] $oldName -> $newName" -ForegroundColor Green }

这里用.Replace()而不是-replace,是有意避开了正则表达式。-replace左侧是正则匹配,如果关键字里包含().[等字符,结果会和预期完全不同。比如关键字(1),用-replace "(1)", ""实际上会删除字符1,留下空括号;用.Replace("(1)", "")才会删除完整的“(1)”。

4.2 增强版:试运行模式、日志和错误记录

生产环境里直接让脚本“闷头改名”风险太高。下面增强版增加了dryRun开关、日志文件和异常捕获:

$keyword = "【完结】" $base = "D:\rename_test" $logFile = "D:\rename_test\rename_log.txt" $dryRun = $true $folders = Get-ChildItem -Path $base -Directory foreach ($folder in $folders) { $oldName = $folder.Name $newName = $oldName.Replace($keyword, "") if ($newName -eq $oldName) { continue } if ([string]::IsNullOrWhiteSpace($newName)) { Write-Warning "新名称为空,跳过: $oldName" Add-Content -Path $logFile -Value "WARN; $oldName; 新名称为空" continue } $targetPath = Join-Path -Path $folder.Parent.FullName -ChildPath $newName if (Test-Path -Path $targetPath) { Write-Warning "目标已存在,跳过: $oldName -> $newName" Add-Content -Path $logFile -Value "WARN; $oldName; $newName; 目标已存在" continue } if ($dryRun) { Write-Host "[DRY RUN] $oldName -> $newName" -ForegroundColor Yellow } else { try { Rename-Item -Path $folder.FullName -NewName $newName -ErrorAction Stop Write-Host "[OK] $oldName -> $newName" -ForegroundColor Green Add-Content -Path $logFile -Value "OK; $oldName; $newName; $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" } catch { Write-Error "重命名失败: $oldName ; $($_.Exception.Message)" Add-Content -Path $logFile -Value "ERROR; $oldName; $newName; $($_.Exception.Message)" } } }

先确认dryRun = $false之前,脚本只会输出将要发生的变更,不会真正执行重命名。日志用分号分隔字段,方便后续导入 Excel 或进行文本过滤。

4.3 PowerShell 方案的适用边界

PowerShell 最大的坑是执行策略。有些机器默认禁止执行.ps1脚本,运行报错时可以用下面的命令查看策略:

Get-ExecutionPolicy

临时放开当前用户限制:

Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

不管是批处理还是 PowerShell,脚本都应该放在待处理目录之外,避免自身的.ps1文件或日志文件被当作业务目录处理。PowerShell 的-Directory只处理目录,不会处理.ps1文件本身,但如果目录内部还包含子目录,脚本默认不递归。确认是否有递归需求后再决定是否加上-Recurse

5. 用 Python 在跨平台环境中批量删除关键字

5.1 Python 方案的使用场景

Python 方案的优势在于跨平台、逻辑清晰、支持复杂规则。比如需要删除多个不同关键字、需要递归子目录、需要把改名记录导出为 JSON 结构化日志,Python 处理起来都更顺手。

5.2 完整脚本

import argparse import logging from pathlib import Path def rename_folders(base: Path, keyword: str, dry_run: bool): if not base.exists() or not base.is_dir(): logging.error("目标目录不存在: %s", base) return for child in base.iterdir(): if not child.is_dir(): continue old_name = child.name new_name = old_name.replace(keyword, "") if not new_name: logging.warning("新名称为空,跳过: %s", old_name) continue if new_name == old_name: continue target = child.with_name(new_name) if target.exists(): logging.warning("目标名称冲突,跳过: %s -> %s", old_name, new_name) continue if dry_run: logging.info("[试运行] %s -> %s", old_name, new_name) else: try: child.rename(target) logging.info("[已执行] %s -> %s", old_name, new_name) except OSError as exc: logging.error("重命名失败: %s, 错误: %s", old_name, exc) if __name__ == "__main__": parser = argparse.ArgumentParser(description="批量删除文件夹名中的关键字") parser.add_argument("--base", required=True, help="待处理的目标目录") parser.add_argument("--keyword", required=True, help="需要删除的文件夹名字符串") parser.add_argument("--dry-run", action="store_true", help="只打印结果,不执行重命名") args = parser.parse_args() logging.basicConfig( level=logging.INFO, format="%(asctime)s | %(levelname)s | %(message)s", datefmt="%Y-%m-%d %H:%M:%S", ) rename_folders(Path(args.base), args.keyword, args.dry_run)

使用方式:

python rename_folders.py --base D:\rename_test --keyword "【完结】" --dry-run python rename_folders.py --base D:\rename_test --keyword "【完结】"

第一次运行加--dry-run,只输出日志不执行修改。确认结果后再去掉参数正式执行。

5.3 脚本中的异常处理与日志设计

Path.iterdir()返回目录下所有子项,child.is_dir()过滤掉普通文件,避免误改文件。old_name.replace(keyword, "")是字面替换,不使用正则,因此括号、点号等特殊字符不会触发意外规则。

child.rename(target)在 Windows 和 Linux 上都可用。如果目标名称已经存在,某些系统会直接报错,某些系统会尝试覆盖,因此冲突提前判断非常必要。脚本用target.exists()提前阻断,避免覆盖已有目录。

dry_run参数是安全设计的核心。CLI 写法比在脚本里改常量更灵活,多个目录可以复用同一个脚本,也方便接入定时任务或构建流水线。

5.4 中文编码问题怎么处理

Python 3 默认源码编码是 UTF-8,日志输出到 Windows 命令提示符时可能因为终端代码页不同显示乱码。可以设置环境变量让输出更稳定:

set PYTHONIOENCODING=utf-8 python rename_folders.py --base D:\rename_test --keyword "【完结】" --dry-run

如果要把日志写入文件,建议在logging.basicConfig里显式指定encoding="utf-8"。在 Python 3.9 以上版本中,FileHandler支持该参数,可以避免 Windows 默认写文件编码带来的乱码问题。

6. 执行后如何验证:确认没有误删和漏改

6.1 重命名前后目录清单对比

执行前先导出一份文件夹清单:

Get-ChildItem -Path D:\rename_test -Directory | Select-Object -ExpandProperty Name | Sort-Object | Out-File D:\before.txt -Encoding UTF8

执行完成后再导出:

Get-ChildItem -Path D:\rename_test -Directory | Select-Object -ExpandProperty Name | Sort-Object | Out-File D:\after.txt -Encoding UTF8

Compare-Object查看差异:

Compare-Object (Get-Content D:\before.txt) (Get-Content D:\after.txt)

预期结果只有带关键字的名称发生改变,没有关键字或不需要变化的名称不应该出现在差异列表中。如果出现额外差异,说明替换规则过宽。

6.2 日志文件检查

执行脚本时如果已输出日志,检查重点有三个:

  • 日志中是否有ERROR行,有则说明存在权限、占用或路径问题。
  • 日志中是否有WARN行,有则说明存在重名冲突或空名称被跳过。
  • 对比日志中成功条数和实际变化文件夹数是否一致。

PowerShell 日志字段用分号分隔,可以用Import-Csv -Delimiter ';'直接加载分析。Python 脚本的日志则可以直接用文本工具搜索关键字。

6.3 手工抽查清单

批量验证不等于全量验证,最后仍建议抽查:

检查项检查方式预期结果
关键字是否完全消失在资源管理器中搜索关键字无匹配结果
文件夹内容是否完整随机打开几个改名后的目录文件数量不变
是否出现空名称文件夹检查名称过短的目录不应出现
重名冲突是否被跳过查看日志 WARN 行冲突项未被覆盖
非目标文件夹是否被改动对比 before/after 差异不应出现在差异列表

7. 常见问题与排查路径

7.1 运行脚本后文件夹名完全没有变化

最常见原因是关键字和实际文件夹名不一致。检查方向:

  • 关键字是否包含多余空格,比如"【完结】 "
  • 文件夹名中的括号是全角还是半角。
  • 批处理脚本是否在错误的目录下运行。
  • 当前执行目录是否指向了%base%

先让脚本输出每个文件夹处理前后的名称,确认匹配没有生效再执行重命名。批处理里可以用echo "!name!" -^> "!new!",PowerShell 里可以临时用Write-Host打印。

7.2 提示“访问被拒绝”或者“另一个程序正在使用”

原因一般有三个:

  • 文件夹被编辑器、终端或资源管理器占用。
  • 当前账号对该目录没有写权限。
  • 目录或文件设置了只读属性。

处理顺序:先关闭可能打开该目录的程序,再用管理员身份运行终端,最后检查只读属性:

Get-ChildItem -Path D:\rename_test -Directory | Where-Object { $_.IsReadOnly } | Format-List FullName

7.3 中文关键字变成乱码或匹配失败

批处理场景下通常是因为脚本文件编码与命令提示符代码页不一致。建议把.bat文件保存为 ANSI 编码,或统一切换到chcp 65001再运行。PowerShell 和 Python 遇到中文关键字时,先确认终端和脚本文件都使用 UTF-8,再执行测试。

7.4 脚本文件放在待处理目录内部

虽然for /dGet-ChildItem -Directory都只处理目录,不会误改.bat.ps1文件,但日志文件如果放在目标目录内部,日志名可能被当成新目录名造成混淆。建议把脚本、日志都放在目标目录之外,保持待处理目录干净。

7.5 重命名后出现同名冲突

同名冲突是批量重命名最常见的问题。比如a【完结】a同时存在,删掉关键字后两个目录都会变成a。脚本在检测到目标已存在时应该跳过并记录警告,防止覆盖。

冲突场景原因建议处理
多个目录删除关键字后同名原始命名不规范先检查冲突列表,人工规划改名顺序
目标目录是空目录目录本身存在,重命名会失败直接跳过,避免覆盖
大小写不同但系统不识别差异Windows 默认不区分大小写在 Linux 上先处理,或先人工合并

8. 从一次重命名到文件整理的最佳实践

8.1 发布重命名脚本前应完成的检查清单

这份清单可以直接复制到自己的项目文档里:

  • 是否已经有完整备份,至少包含目录名清单。
  • 是否在最小测试目录跑通过脚本。
  • 是否在试运行模式下确认所有输出符合预期。
  • 关键字是否包含正则特殊字符、空格、全角符号。
  • 脚本和日志是否放在待处理目录之外。
  • 是否确认目标存在同名文件夹时不会被覆盖。
  • 是否记录了执行前的文件夹清单。
  • 是否准备好失败后的回滚方案。

8.2 推荐的执行顺序

第一次处理真实目录时,不要一次性处理所有文件夹。建议先拷贝一个包含典型名称的小目录验证脚本,然后把脚本改成直接处理真实目录,但保留dry_run模式。确认试运行结果后,再执行正式重命名。

好的脚本应该具备幂等性。即第一次运行把course_old_v1改成course_v1后,第二次运行不会继续修改course_v1。上面三个方案都通过比较“新名称是否等于旧名称”实现了这个效果。幂等性很重要,因为脚本可能因为网络中断、权限问题执行到一半,修复环境后需要安全重跑。

8.3 可以继续扩展的方向

如果目录结构更复杂,可以扩展出多个变体需求。例如递归处理子目录,把for /d改成for /r /d,或者在 PowerShell 的Get-ChildItem里加上-Recurse。文件名和文件夹名混合处理时,把文件夹过滤条件去掉即可。需要批量替换多个关键字时,可以把关键字列表写到配置文件里,脚本启动时循环读取。

用脚本做批量重命名的本质,是让机械化的修改过程变得可预期、可回滚、可重复。它解决的不只是“省一次鼠标点击”,而是让后续的整理动作更规范。建议把一个通用的rename_folders.py脚本保存为本地工具,配上必要的日志路径和备份脚本,下次面对杂乱目录时就能直接复用,而不是每次临时搜索解法。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 13:13:32

Where Is My Mind吉他谱教学:分解和弦与琶音技巧详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 13:12:59

AI漫画翻译管线实战:从OCR到图像修复保留原画质感

漫画翻译并不是把对白逐句改掉那么简单。真正影响观感的是,原图经过检测、识别、翻译、抹字、嵌字这些步骤后,是否还能保持原始画作的线条、网点和整体氛围。Mee Manga Translator 这类 AI 漫画翻译工具的核心价值,就是在完成语言转换的同时保…

作者头像 李华
网站建设 2026/9/7 13:12:36

NVIDIA V100 PCIe与SXM2形态深度对比:选型策略与性能实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 13:11:38

Agentic RAG实战:单智能体工具调用打造本地知识库问答助手

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 13:11:02

Verilog核心解析:assign、always组合逻辑与时序逻辑对比

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 13:09:02

嵌入式Linux Modbus RTU开发实战:串口配置、协议解析与调试技巧

嵌入式Linux下做Modbus RTU开发,听起来像是个基础活儿,但真要一次把串口调通、把传感器数据读准,坑还是不少。这个项目说白了就三件事:把嵌入式Linux的串口配置对,按Modbus RTU协议把请求帧发出去,再把从站…

作者头像 李华