news 2026/9/30 7:43:24

批量文件名大小写转换:4种跨平台实用方法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
批量文件名大小写转换:4种跨平台实用方法

拍了一堆照片、下了一堆资料、拷了一堆项目文件,打开文件夹一看,DSC_0234.JPG、dsc_0234.jpg、ReadMe.txt、README.txt混在一起,强迫症当场就犯了。更麻烦的是,有些程序只认固定大小写的文件名,名字里大写字母一多,传上服务器或者扔给同事,直接就“文件不存在”。

把文件名里的大写字母批量转成小写,听起来是小需求,真做起来还真有讲究。Windows 和 Linux 的大小写规则不一样,批处理和 PowerShell 的写法完全不同,直接手动改几百个文件又太愚蠢。这篇就把我实测过、并且至今还在用的 4 个方法整理出来,从系统自带命令到跨平台脚本都有,普通用户和程序员都能抄作业。

在动手之前,我建议先把下面三个背景知识过一遍。搞清楚之后你再选择方法,会少踩很多坑。

1. 动手前先想清楚:这些文件到底该不该动

1.1 大小写混乱的常见场景

我遇到过最典型的三类情况。第一类是相机和手机导出的照片,DSC_0234.JPG、IMG_0025.Png这种大写扩展名非常常见,素材一多,同一天拍的照片就会出现两种扩展名写法。

第二类是开发部署场景。项目在 Windows 上开发,文件名随手写成UserInfo.js,部署到 Linux 服务器后,Nginx 或者后端代码却用小写userinfo.js去访问。Linux 文件名是严格区分大小写的,这种问题查起来极其痛苦,页面白屏一整天,最后发现只是大小写不一致。

第三类是批量下载的资源,解压出来命名混乱,大小写全凭上传者心情。如果你也有类似需求,这篇文章里的方法可以直接解决。

1.2 动手前的两道保险:备份与预览

批量改名的第一步永远是备份。Windows 上我习惯用 robocopy:

robocopy D:\素材 D:\素材_备份 /E

Linux 下直接:

cp -r /data/素材 /data/素材_备份

别嫌占磁盘空间。几百个文件念错一个字符,可能就是几个小时的工作量白费。

第二步是预览。后面给的每个方案我都会带上“只看不改”的命令行参数。你先跑一遍,看它打算把哪些文件改成什么名字,确认清单没问题,再真正执行。这个习惯比任何备份都重要,因为我踩过太多次“以为改对了,其实规则写错了”的坑。

1.3 三个平台的大小写规则,完全不一样

先看一张对比表,后面所有方法的注意事项都跟这张表有关。

平台是否区分文件名大小写同一目录能否同时存在A.txt和a.txt
Windows默认不区分,但保留大小写不能,系统视为同一文件
Linux严格区分可以,是完全不同的两个文件
macOS默认不区分(可开启区分)默认不能,取决于磁盘格式

这个差异会造成一个非常迷惑的现象:在 Windows 上把ABC.TXT改成abc.txt,系统会提示“目标文件已存在”,但事实上你要改的就是它自己。后面 PowerShell 那节我会专门讲这个坑。

2. 方法一:Windows 自带 PowerShell,复制就能用

2.1 为什么不用记事本写 bat

你搜“批量改文件名”,大概率会搜到一堆.bat批处理脚本。我劝你直接跳过。批处理没有内置的字符串大小写转换函数,想实现逐字符判断,代码会写成好几层 for 循环嵌套,别说新手,我看着都头大。

PowerShell 是 Windows 10 和 11 自带的,右键开始菜单或者 Shift+鼠标右键就能打开终端。它内置了.ToLower()字符串方法,配合管道,两行命令就能解决问题。不需要装任何额外软件,这一点很方便。

2.2 单层目录:三条命令直接跑

打开 PowerShell,cd 到文件所在目录,执行:

Get-ChildItem -File | ForEach-Object { Rename-Item -LiteralPath $_.FullName -NewName $_.Name.ToLower() }

解释一下:Get-ChildItem -File列出当前目录下所有文件,ForEach-Object逐个处理,$_.Name.ToLower()生成小写新文件名,Rename-Item执行重命名。-LiteralPath是为了防止文件名里包含[、]这类特殊字符时被通配符解析。

在真正执行之前,我强烈建议先跑一遍预览:

Get-ChildItem -File | Where-Object { $_.Name -cne $_.Name.ToLower() } | ForEach-Object { Write-Host $_.Name "->" $_.Name.ToLower() }

-cne是区分大小写的比较,只有真的包含大写字母的文件才会被列出来。你看着这份清单确认没问题,再去执行正式命令。

2.3 递归处理全部子文件夹

几层子目录套着?加-Recurse就行:

Get-ChildItem -Path . -File -Recurse | ForEach-Object { $new = $_.Name.ToLower() if ($_.Name -cne $new) { Rename-Item -LiteralPath $_.FullName -NewName $new } }

这段代码会自动遍历当前目录下的所有子文件夹,把每个文件都检查一遍。有点需要注意的是,如果某些子文件夹的路径权限不够,或者文件正被另一个程序占用,重命名会报错。报错的提示是红色的,不要慌,把正在开着的那几个文件关掉再跑一次就行。

2.4 Windows 特有的“文件已存在”坑

如果你只执行了第一条命令却没有加判断,很容易看到这样的报错:Rename-Item : 无法创建文件“abc.txt”,因为已存在同名的文件“abc.txt”。

原因就是开头那张表里写的,Windows 不区分文件名大小写。ABC.TXT改成abc.txt,系统认为目标已经存在,但实际上目标就是自己。不同版本的 PowerShell 对这种情况的处理不完全一致,所以我推荐你使用带Where-Object或if ($_.Name -cne $new)判断的版本,只改名真正变化的文件,并且在Rename-Item后面追加-ErrorAction SilentlyContinue来忽略那些“假冲突”的错误。

还有一个常见问题是有中文文件名。.ToLower()只处理英文字母,对中文没有任何影响,我的文件_v2.TXT会被改成我的文件_v2.txt,中文原样保留,放心跑。

3. 方法二:Linux/macOS 终端,一条命令批量搞定

3.1 rename 命令的版本陷阱

很多教程会告诉你 Linux 下用 rename 一行搞定,但这条命令在不同发行版上完全是两个物种。Ubuntu/Debian 自带的是 Perl 版 rename,支持完整的正则表达式,写法是:

rename 'y/A-Z/a-z/' *.JPG

而 CentOS/RHEL/Fedora 自带的是 util-linux 版 rename,它只做字符串替换,不支持字符范围映射。如果直接照抄上面的命令,大概率会得到报错或者完全没有生效。

建议你先执行rename --version看是哪个版本。如果是 util-linux 版,或者你根本不想区分这些,直接用 3.2 节的通用方案。

3.2 最通用的 for + tr 组合

这个方法不依赖任何特定版本的 rename,只要是个 Bash 环境就能跑。最简单的单目录版本:

for f in *; do low=$(printf '%s' "$f" | tr 'A-Z' 'a-z') [ "$f" = "$low" ] && continue mv -n -- "$f" "$low" done

逐行拆解:for f in *遍历当前目录的每个条目;printf '%s' "$f" | tr 'A-Z' 'a-z'把文件名中的大写字母替换成小写,tr命令的本质是字符映射;[ "$f" = "$low" ]判断有没有变化,没有变化就跳过;mv -n表示如果目标名字已经存在就不覆盖,--是为了防止文件名以-开头时被当成命令参数。

实测下来,这段代码对空格、中文、括号都能正确处理,因为变量都加了双引号。

3.3 递归处理子目录并防止覆盖

如果要在子目录里递归处理所有文件,用 find 组合:

find . -type f -print0 | while IFS= read -r -d '' f; do dir=$(dirname -- "$f") base=$(basename -- "$f") low=$(printf '%s' "$base" | tr 'A-Z' 'a-z') [ "$base" = "$low" ] && continue mv -n -- "$f" "$dir/$low" done

这里用了-print0配合read -d '',专门应对带空格、换行符的文件名。dirname和basename把路径和文件名拆开,转小写得新名后,仍然拼回原来的目录。

mv -n这个参数极其重要。在 Linux 上,Foo.txt和foo.txt可以同时存在,如果你把一个转小写后的名字撞上了已有的另一个文件,mv默认会直接覆盖掉目标。加上-n后遇到冲突就跳过,绝不静默覆盖,这个细节救过我一次。

3.4 中文文件名在终端里的边界情况

如果你要处理的目录里有中文文件名,终端本身一般没问题,前提是系统 locale 是 UTF-8。执行locale看输出,只要带上UTF-8就行。一旦发现中文变成乱码,多半是 SSH 客户端或者终端编码设置不对,跟改名命令无关。

还有一个细节:macOS 默认的文件系统(APFS)是不区分大小写的,所以跟 Windows 一样,在同一目录里不会出现“重名”。你在 mac 上跑完 for+tr 后,如果提示mv: rename ... to ...: File exists,大概率也是遇到了大小写变体是指向同一个文件的“假冲突”,可以忽略,或者像我一样先列一下预览,把真正改名的文件筛选出来。

4. 方法三:Python 脚本,全平台通用还带安全预览

4.1 为什么还需要一个脚本

PowerShell 只在 Windows 上能用,for+tr 在 Windows 上要装 Git Bash 才能跑。如果你平时要在系统之间来回切换,或者需要定制规则,比如只改扩展名、只处理某个后缀、预览后确认再执行,那 Python 脚本是最省心的。

我不推荐直接去下载网上的“批量改名神器”,原因有两个:一是不明来源的 exe 有安全风险;二是这种软件往往限制多,文件夹数量一大就收费。Python 脚本完全免费,自己写的代码自己心里有底。

4.2 完整脚本:字典动作、递归、预览、执行一应俱全

把下面这段保存为tolower.py,放在任何目录都能用:

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 批量把文件名中的大写字母改为小写。 用法示例: python tolower.py # 预览当前目录 python tolower.py --exec # 真正执行当前目录 python tolower.py -r --exec D:\素材 # 递归处理 D:\素材 下所有文件 """ from pathlib import Path import argparse def convert(path: Path, keep_ext: bool, only_file: bool, dry_run: bool): if only_file and path.is_dir(): return if keep_ext and path.is_file(): new_name = path.stem.lower() + path.suffix else: new_name = path.name.lower() if new_name == path.name: return target = path.with_name(new_name) if dry_run: print(f"[预览] {path} -> {target}") return try: path.rename(target) print(f"[已改] {path} -> {target}") except FileExistsError: print(f"[跳过] 目标已存在(不同文件): {target}") except Exception as e: print(f"[失败] {path}: {e}") def main(): parser = argparse.ArgumentParser(description="批量把大写文件名转小写") parser.add_argument("path", nargs="?", default=".", help="要处理的目录,默认当前目录") parser.add_argument("-r", "--recursive", action="store_true", help="递归处理子目录") parser.add_argument("--dirs", action="store_true", help="文件夹名也一并转小写") parser.add_argument("--keep-ext", action="store_true", help="只转主文件名,扩展名保持不变") parser.add_argument("--dry-run", action="store_true", default=True, help="预览模式,默认开启") parser.add_argument("--exec", action="store_true", help="真正执行改名,必须显式加上这一步") args = parser.parse_args() root = Path(args.path).resolve() if not root.is_dir(): print(f"路径不存在或不是目录: {root}") return dry_run = not args.exec # 默认只预览,除非你明确传入 --exec if args.recursive: # 按路径深度降序:先处理深层文件,再处理浅层目录, # 这样即使目录名也要改,也不会因为路径失效而中断 items = sorted(root.rglob("*"), key=lambda p: len(p.relative_to(root).parts), reverse=True) else: items = sorted(root.iterdir()) for p in items: convert(p, args.keep_ext, not args.dirs, dry_run) if __name__ == "__main__": main()

4.3 关键逻辑说明:预览设计、深度排序和跨平台“假冲突”

这个脚本最核心的设计是“默认预览,强制显式执行”。--dry-run默认值为 True,你直接运行python tolower.py,它只会列出一堆[预览]行,不会动任何文件。只有当你明确加上--exec,它才会真正执行。我故意这么设计的,因为批量操作最怕的就是“我以为会 A,结果它做了 B”。

第二个关键点是sorted(..., reverse=True)按路径深度降序。如果文件夹名称也要转小写,你先处理文件夹本身再处理子文件,路径就断了,程序会报错找不到文件。按深度从深到浅处理,先把所有文件改名,最后再动文件夹,就不会出问题。

第三个关键点是except FileExistsError。这里处理的正是 Windows 上的“假冲突”:当ABC.txt改成abc.txt,系统可能认为目标已存在,但实际上目标就是自己。不同版本的 Python 在 Windows 上对这种操作的行为有差异,有的能正常执行,有的会抛出 FileExistsError,捕获一下更安全。如果冲突的是另一个真正的文件,这个异常也能拦住,防止意外覆盖。

4.4 顺带排查“文件名乱码”的问题

这个话题经常被搜到,但我在这里必须泼一盆冷水:批量转大小写的脚本解决不了文件名乱码。

乱码是编码问题,常见表现是中文显示成浣犲ソ或者ä¸Â。这种问题通常是因为文件名的编码和当前系统解释的编码不一致,比如本来是 GBK 编码的名字被按 UTF-8 解析,或者反过来。遇到这种情况,Python 脚本可以做一次编码猜测并转换,但成功率不一:

try: fixed = name.encode('latin-1').decode('gbk') except Exception: fixed = name

encode('latin-1').decode('gbk')这类补救方式只对特定场景有效,不是万能钥匙。我的建议是:先把乱码问题单独拎出来处理,不要跟大小写转换混在一起。文件名一旦出现乱码,先用第三方小工具或者系统自带的编码转换确认恢复效果,再决定是否继续改大小写。

5. 方法四:图形化改名工具,拖出来点几下就完事

5.1 微软 PowerToys 的 PowerRename,Windows 上最省心

如果你不想碰代码,Windows 下我首推 PowerToys 里的 PowerRename。PowerToys 是微软官方出品的一组实用工具合集,免费开源,Microsoft Store 里直接搜“PowerToys”就能装。

装完后,在资源管理器里选中一堆文件,右键菜单多了一个“PowerRename”。打开后的界面非常直观,主要的操作方式是:

  1. 在 Search 框中输入(.*)(意思是匹配任意文件名)。
  2. 在 Replace 框中输入$1(意思是保留匹配到的完整原文件名)。
  3. 在右上角的 Case 下拉菜单里选择 Lowercase。
  4. 预览列表会实时显示每个文件改后的效果。
  5. 确认无误,点击 Rename。

这个工具的好处是预览是实时的,而且支持正则,如果你顺带想去掉文件名里的括号、统一把abc - 001.jpg改成abc_001.jpg,都在同一个界面里完成。它还能只作用于文件名主体而不动扩展名,勾选对应的选项就行。

5.2 老牌工具 Advanced Renamer,规则更丰富

另一款我实测过多次的工具是 Advanced Renamer,老牌免费软件,Windows 平台。它强在规则可以叠加,比如先给文件名加前缀,再把扩展名转小写,再插入日期,一套流程自动跑完。

操作流程:

  1. 把文件拖进主窗口。
  2. 左侧选择 “Case / Upper / Lower” 规则,设置成 Lowercase。
  3. 上方实时预览新文件名。
  4. 点击 Start Batch 执行。

如果你跟热搜词“批量修改文件名前缀”“批量去除文件名里的括号”打过交道,Advanced Renamer 的 Replace 规则也能一并处理。选好规则后预览,再执行,和 PowerRename 的体验差不多,但它支持的规则类型更多。

5.3 图形工具的适用与边界

图形化工具最适合两类人:一是不习惯命令行的普通用户,二是要处理海量文件并且需要视觉确认结果的人。

需要接受它的两个边界:第一是只有 Windows 版本,Linux/macOS 上的替代品要么质量参差,要么要折腾 Wine;第二是它对大量文件夹的递归处理效果不如命令行灵活,虽然 PowerRename 和 Advanced Renamer 都能操作子文件夹,但规则一复杂,界面上的状态反而比代码更难排查。

另外提醒一句,下载任何改名工具时,尽量去官网或者微软官方渠道,别在下载站随便点“高速下载”。市面上有不少打包了推广软件的同名工具,装完会附带一堆全家桶。

6. 实操心得与避坑清单

6.1 我踩过的四个坑

第一个坑是处理目录名顺序不对。有一次我用最早的 Python 脚本,先改了外层文件夹名,再去处理里面的子文件,脚本直接抛 FileNotFoundError,因为路径引用已经失效。后来一律先深后浅,彻底解决。

第二个坑是 Windows 上判断“目标是否已存在”的假阳性。我在脚本里写if target.exists(): continue,跑了一遍发现所有文件全被跳过,因为 Windows 把ABC.txt和abc.txt视为同一个文件,target.exists()一直返回 True。解决方案是别用 exists 判断,直接 try rename,用异常处理兜底。

第三个坑是 Linux 上mv静默覆盖。有一次改Foo.txt成foo.txt,而目标目录里恰好已有一个内容不同的foo.txt,我不加-n直接 mv,旧文件被覆盖。血的教训,从此所有批量改名一律带-n。

第四个坑是改完名后项目引用全乱。开发项目里,文件名大小写一变,所有 import、图片路径、配置引用全部失效。这个问题的解法不是改名后看运气,而是改名之前先全局搜索一遍引用。如果项目是 git 仓库,用git mv而不是mv,这样 Git 才能正确识别成重命名而不是删除加新增。

6.2 速查表:哪个方法适合你

你的情况推荐使用
Windows 用户,不想安装任何东西方法一:PowerShell
Linux/macOS 用户,喜欢命令行方法二:for + tr
需要跨平台复用,或要自定义规则方法三:Python 脚本
不习惯命令行,想可视化预览方法四:PowerRename / Advanced Renamer
只改扩展名,不动文件主体方法三加--keep-ext或工具里的对应选项
需要递归处理深层目录方法一、二、三都支持,优先方法三

6.3 特殊软件场景:别乱改项目依赖文件名

最后特别提醒一种情况:涉及软件工程类项目引用文件的时候,比如 SolidWorks 装配体、PS 素材、AE 工程、代码仓库里的资源文件,这类文件之间是通过文件名和路径相互引用的。如果你把某个零件文件从Part_001.SLDPRT改成part_001.sldprt,同时没有通过软件自身的打包功能,装配体很可能打不开,报“文件名无效或被锁住”。

这类场景下,正确做法是使用软件自带的打包/另存为功能,让它同步更新引用关系,而不是在资源管理器里直接改。如果只是在做素材归档、照片整理、编码规范统一这类“文件本身是独立个体”的场景,那随便用上面的哪种方法都行。

我自己的习惯是,每次批量改名都先用预览模式输出一个清单,人眼扫一遍,再执行。改完之后,把项目重新打开、素材重新加载一遍,确认没有红叉、没有 404,才算真正完成。文件名大小写这件事,本身不复杂,复杂的是改完之后的连锁反应——但只要你始终记得“备份加预览”这两个词,基本就不会出大问题。

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

OpenStack虚拟机迁移实战:冷迁移与热迁移原理与运维指南

1. 迁移前的认知与选型1.1 迁移到底在解决什么问题做OpenStack平台运维的人,几乎都会遇到这样的场景:某台计算节点要下线维护,或者某台宿主机负载告警,甚至只是单纯想调整资源分布,这时候你就需要把上面的云主机实例挪…

作者头像 李华
网站建设 2026/9/30 7:42:25

工程建筑行业软件开发案例:从装修咨询到电子签约与工程监控

装修服务从内容浏览转化为实际工程,通常需要经过需求沟通、付费咨询、设计师接单、合同签署和施工管理等多个阶段。如果装修内容、咨询订单、设计方案、施工进度和建材商品分别存在于不同渠道,用户和服务人员之间容易出现信息衔接不连贯的问题。根据某公…

作者头像 李华
网站建设 2026/9/30 7:39:25

SpringBoot+Vue冷链物流管理系统实战:从数据库设计到部署

冷链物流系统这几年在毕业设计和中小型企业里出镜率很高,但很多所谓冷链系统其实就是普通物流系统换个壳,温控、报警、冷链环节追溯这类核心功能做得扎实的不多。这次以一个基于 SpringBootVue 的 BS 模式冷链物流管理系统为例,后端是 Spring…

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

yocto: 23-linux bbappend

第13课: 这一课是 Yocto BSP 开发最重要的一课。# Yocto BSP 开发第13课:linux-*.bbappend 深度解析 摘要:本文深入讲解 Yocto BSP 开发中最重要的 linux-*.bbappend 技术。通过对比错误做法与正确方法,详细解析 bbappend 的工作原理、目录结构建立、配置修改、补丁应用、设…

作者头像 李华