概述和构想
笔者在工作中,遇到了一个需要批量对文件或者文件夹进行改名的操作需求。用户在日常工作中,积累了大量的工作文件,这些文件都按照原来的组织方式,放在很多文件夹中。但另一个业务需要将这些文件夹进行分类和再次组织,由于原有业务并没有考虑到这个要求,没有提供合适的编码和命名方式,就需要对这些文件夹按照新的组织方式进行重新进行重新命名操作。
当然小批量和单个的文件夹,可以使用手动完成(使用资源管理器或者命令行)。但如果考虑到如果有几千个这样的文件夹,手动操作的代价就非常繁琐了。更麻烦的是,如果更名的依据来自于业务需求,没有特定清晰的模式(如编码规则),就更不好处理了。
为此,笔者在本文中提出并实现了一种批量的基于映射文件的操作方式。用户通过维护一个命名映射文件,并执行一个重命名脚本指令,就可以达成批量重命名文件夹的目的。
在实践过程中,笔者觉得这个需求和处理方案都比较有代表性,也是常见的系统运维工作,遂著文记录分享之。
映射文件
到这里读者应该可以看到,这个模式的核心,就是这个映射文件,也可以理解成为控制文件。
笔者设计的映射文件的结构和示例如下:
map.csv
# 文件夹重命名映射表
# 格式:旧文件夹名称,新文件夹名称
# 注意:请确保旧文件夹在当前目录下存在
旧文件夹名,新文件夹名
成都七中,510100成都七中
达州一中,511700达州一中
temp_data,final_data_2024
2023_backup,archive_2023q4
client_raw_data,client_processed_data
development,production_ready
test_env,staging_environment
documents_2023,documentation_archive
就是简单的csv格式,逗号分隔。每个有效行包括旧文件夹和要命名的新文件夹名称。可以包括空行和注释行(#开头),然后在代码中,忽略这些无效行的处理。
这个文件可以按照需要手动编辑,但最好的方式肯定是数据库查询后生成,所幸很多数据库管理工具都有可以直接基于查询结果生成和导出csv的功能。
Linux版本
映射文件准备好了之后,就需要匹配的文件处理脚本来进行处理。基于方便使用和移植的考虑,这个脚本应该是一个操作系统可以直接内置支持的脚本程序,无需依赖外部执行环境和程序。
我们先以Linux系统为例,它的终端环境,本身就是一个可执行环境,默认的脚本执行程序就是如bash和sh这种程序,并使用配套的脚本,就可以在无外部依赖的情况下进行相关的文件操作和批量处理。
下面就是一个名为rnm.sh的bash脚本程序:
rnm.sh
#!/bin/bash
# 脚本:rnm.sh
# 用法:./rnm.sh [map.csv]
if [ $# -ne 1 ]; then
# echo "用法: $0 <索引文件>"
# echo "索引文件格式: 旧文件夹名,新文件夹名"
echo "使用默认索引 map.csv"
INDEX_FILE="map.csv"
else
INDEX_FILE="$1"
echo "使用索引文件 $1"
fi
if [ ! -f "$INDEX_FILE" ]; then
echo "索引文件 $INDEX_FILE 不存在 "
exit 1
fi
# 读取索引文件并执行重命名
while IFS=',' read -r old_name new_name || [ -n "$old_name" ]; do
# 去除可能的空格
old_name=$(echo "$old_name" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
new_name=$(echo "$new_name" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [[ -z "$old_name" || -z "$new_name" || "$old_name" =~ ^# ]] ; then
# echo "跳过空行和注释"
continue
fi
if [ -d "$old_name" ]; then
if [ ! -e "$new_name" ]; then
echo "重命名: $old_name -> $new_name"
mv "$old_name" "$new_name"
else
echo "警告: 目标文件夹 $new_name 已存在,跳过 $old_name"
fi
else
echo "警告: 源文件夹 $old_name 不存在"
fi
done < "$INDEX_FILE"
echo "重命名完成!"
配合前面的映射文件,相关的执行调用方式和处理结果如下:
js
./rnm.sh
使用默认索引map.csv
跳过空行
跳过空行
警告: 源文件夹 旧文件夹名 不存在
重命名: 成都七中 -> 510100成都七中
重命名: 达州一中 -> 511700达州一中
警告: 源文件夹 temp_data 不存在
警告: 源文件夹 2023_backup 不存在
警告: 源文件夹 client_raw_data 不存在
警告: 源文件夹 development 不存在
警告: 源文件夹 test_env 不存在
警告: 源文件夹 documents_2023 不存在
重命名完成!
简单说明:
- 脚本编写可以使用通用的文件处理程序,笔者直接使用vi
- 脚本编写完成后,需要赋予其执行权限( chmod a+x rnm.sh)
- 执行前,需要准备好要处理的文件夹,其上级文件夹作为工作文件夹
- 将脚本文件和映射文件都放在工作文件夹中
- 命令行的参数是可选的,可以指定使用特定的映射文件,否则会使用默认映射文件(map.csv)
- 程序自动忽略空行和注释行和错误格式信息
- 如果源文件夹不存在,提示错误信息
- 如果目标夹已存在,提示错误信息
- 正常处理,提示正常处理信息
为了方便和效率,其实上面提供的代码,基本上都是AI生成的,但笔者的运气不太好,虽然大的框架没有问题,但实现中有一些细节进行了调整,所以看起来还没有到完全无懈可击的程度。当然,如果没有AI辅助,实现相关的工作,可能需要查询大量资料和进行更多的实验,确实更加低效和费时。
这里补充一下笔者所使用的提示词(使用的模型是deepseek-V3.1:671b):
请帮我在Linux系统上,编写一个sh脚本,可以按照一个索引map信息的内容,对当前目录中的文件夹进行批量改名
Windows版本
为了保存操作的通用性,利于类似的思路,笔者在Window系统上也实现了相应的版本。考虑到维护和使用的简便,同样实现的是命令行方式,使用相同的映射文件,但执行环境改成了PowerShell。使用方式一致。
下面是相关的PS脚本:
rnm.ps1
# 脚本:rnm.ps1
# 用法:.\rnm.ps1 [map.csv]
param(
[string]$IndexFile = "map.csv"
)
# 设置控制台编码为UTF-8
$OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::InputEncoding = [System.Text.Encoding]::UTF8
chcp 65001 > $null
# 检查是否提供了参数
if ([string]::IsNullOrEmpty($IndexFile)) {
$IndexFile = "map.csv"
Write-Host "使用默认索引 map.csv"
} else {
Write-Host "使用索引文件 $IndexFile"
}
# 检查索引文件是否存在
if (-not (Test-Path $IndexFile)) {
Write-Host "索引文件 $IndexFile 不存在" -ForegroundColor Red
exit 1
}
try {
# 读取索引文件(指定UTF-8编码)
$lines = Get-Content $IndexFile -Encoding UTF8
} catch {
# 如果UTF-8失败,尝试默认编码
$lines = Get-Content $IndexFile
}
# 处理CSV文件中的BOM(字节顺序标记)
if ($lines.Count -gt 0 -and $lines[0].StartsWith("ï>>¿")) {
$lines[0] = $lines[0].Substring(3)
}
# 读取索引文件并执行重命名
foreach ($line in $lines) {
# 跳过空行和注释行(以#开头)
if ([string]::IsNullOrWhiteSpace($line) -or $line.Trim().StartsWith("#")) {
continue
}
# 按逗号分割行
$parts = $line.Split(',', 2)
if ($parts.Length -lt 2) {
Write-Host "警告: 行格式不正确,跳过: $line" -ForegroundColor Yellow
continue
}
# 去除空格
$oldName = $parts[0].Trim()
$newName = $parts[1].Trim()
# 检查名称是否为空
if ([string]::IsNullOrWhiteSpace($oldName) -or [string]::IsNullOrWhiteSpace($newName)) {
Write-Host "警告: 旧名称或新名称为空,跳过: $line" -ForegroundColor Yellow
continue
}
# 检查源文件夹是否存在
if (Test-Path $oldName -PathType Container) {
# 检查目标文件夹是否已存在
if (-not (Test-Path $newName)) {
Write-Host "重命名: $oldName -> $newName" -ForegroundColor Green
Rename-Item $oldName $newName
} else {
Write-Host "警告: 目标文件夹 $newName 已存在,跳过 $oldName" -ForegroundColor Yellow
}
} else {
Write-Host "警告: 源文件夹 $oldName 不存在" -ForegroundColor Yellow
}
}
Write-Host "重命名完成!" -ForegroundColor Green
简单说明:
- 笔者使用notepad++来编辑这个脚本文件
- 可能需要赋予当前用户和环境执行脚本的权限(后详)
- 注意脚本文件的编码方式,必须是"UTF8-BOM",否则会乱码
- 注意脚本中的字符集和PowerShell代码页的设置(chcp 65001 > $null)
- 其他操作逻辑,基本上和Linux版本相同,具体实现的细节,都是匹配PS的
这里有一些坑,就是PowerShell对于UTF8字符集的支持不是很好,很容易出现乱码,需要相关设置和配置。默认的编辑和存储方式是不行的。否则会出现下面的情况:

还有就是运行中,可能遇到无法执行ps脚本程序的情况,需要为当前用户打开脚本执行权限:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
扩展
由于时间和场景的限制,本文只讨论的处理大批量子文件夹的情况,但显然实际的需求可能会更复杂一点。比如需要重命名文件,文件夹递归操作等等。但基本逻辑和操作都是一致的。无非就是在脚本中增加文件类型的判断,映射信息的补充等等,这里就不再展开了。
显然,本文提出的技术方案也是有通用性和可移植性的。用户也不需要再次编写程序,只需要维护映射文件,就可以进行满足业务需求的重命名操作。
小结
本文通过笔者在工作中遇到的一个需要大批量对文件夹进行重命名的需求,探讨了一个基于映射文件的批量重命名处理的技术方案。探讨了其基本原理,映射文件的格式和生成方式,并提供了配套的可以在Linux系统和Window环境中允许的脚本程序。