批量重命名工具进化史:从单行命令到交互式菜单的完整实现
需求
AlmaLinux 系统,有一个文件夹里的几百个文件,要把文件名全部改成随机的五位字母数字组合,保留原扩展名。
听起来很简单对吧?但写着写着,需求就越来越多了。
第一版:快速出活
最直接的方式就是用 Python,几行代码搞定:
import os, random, string
chars = string.ascii_letters + string.digits
for f in os.listdir('.'):
if os.path.isfile(f) and f != 'rename.py':
name, ext = os.path.splitext(f)
new_name = ''.join(random.choice(chars) for _ in range(5)) + ext
os.rename(f, new_name)
print(f'{f} -> {new_name}')逻辑很简单:遍历当前目录所有文件,生成5位随机字母数字,保留扩展名,重命名。排除脚本自身。
不过马上想到几个问题:
- 随机生成可能会重复,万一两个文件生成相同的名字就冲突了
- 没有确认提示,手滑就全没了
- 只能跑在当前目录,不能指定目录
第二版:加安全机制
加一个 used_names 集合来去重,再加确认提示。
used_names = set()
for filename in files:
name, ext = os.path.splitext(filename)
while True:
random_name = generate_random_name(5)
if random_name not in used_names:
used_names.add(random_name)
break
new_filename = random_name + ext
os.rename(filename, new_filename)这样再也不会撞名了。但每次改参数(比如想改成8位、想加前缀后缀)都要改代码,很麻烦。
第三版:命令行参数支持
用 argparse 模块加参数支持:
# 用法
python3 rename.py -d /path/to/dir -l 8 -p "IMG_" -s "_v2" -n参数说明:
-d目标目录-l随机名称长度-p文件名前缀-s文件名后缀-n模拟运行(只预览不改)-f强制运行(跳过确认)
这样灵活多了,但问题来了——每次都要敲一长串命令,记不住参数。
第四版:交互式菜单
考虑到不是所有人都习惯命令行,加一个交互式菜单,双击脚本就能用。
菜单设计:
============================================================
批量文件重命名工具 v2.0
============================================================
请选择操作模式:
1. 快速重命名(使用默认设置)
2. 自定义重命名
3. 查看/修改默认设置
4. 查看操作历史
5. 退出模式1:快速重命名
直接用预设的默认参数,回车就执行,适合经常处理同样任务的场景。
模式2:自定义重命名
一步步问你:
自定义设置:
----------------------------------------
目录 (默认当前目录):
随机名称长度 (默认5):
文件名前缀 (默认无):
文件名后缀 (默认无):
字符集选项:
1. 字母和数字 (默认)
2. 仅字母
3. 仅数字
4. 自定义字符集
模拟运行 (不实际重命名)? (y/N):所有问题都有默认值,直接回车就用默认,不用全填。
模式3:保存默认设置
把常用参数保存下来,下次用"快速重命名"就能直接用。设置保存在 ~/.rename_tool_config.json:
{
"default_length": 5,
"default_prefix": "IMG_",
"default_suffix": "",
"default_directory": "/home/user/photos",
"default_charset": "alnum",
"custom_charset": "",
"history": [
"重命名了 10 个文件在 /home/user/photos (长度:5, 前缀:'', 后缀:'')"
]
}模式4:操作历史
每次成功的重命名操作都会被记录下来,方便追溯。
完整代码
最终版本的完整代码(核心结构):
#!/usr/bin/env python3
import os, random, string, sys, json, argparse
CONFIG_FILE = os.path.expanduser("~/.rename_tool_config.json")
def generate_random_name(length=5, charset_type="alnum", custom_chars=""):
"""生成随机名称"""
if charset_type == "alnum":
chars = string.ascii_letters + string.digits
elif charset_type == "letters":
chars = string.ascii_letters
elif charset_type == "digits":
chars = string.digits
elif charset_type == "custom" and custom_chars:
chars = custom_chars
else:
chars = string.ascii_letters + string.digits
return ''.join(random.choice(chars) for _ in range(length))
def rename_files(directory, length, prefix, suffix, charset_type,
custom_chars, dry_run, config=None):
"""核心重命名逻辑"""
os.chdir(directory)
files = [f for f in os.listdir('.') if os.path.isfile(f)]
script_name = os.path.basename(__file__)
if script_name in files:
files.remove(script_name)
renamed_count = 0
used_names = set()
for filename in files:
name, ext = os.path.splitext(filename)
while True:
random_name = generate_random_name(length, charset_type, custom_chars)
new_filename = f"{prefix}{random_name}{suffix}{ext}"
if new_filename not in used_names:
used_names.add(new_filename)
break
if dry_run:
print(f"[模拟] {filename} -> {new_filename}")
else:
os.rename(filename, new_filename)
print(f"{filename} -> {new_filename}")
renamed_count += 1
# 记录历史
if config and not dry_run and renamed_count > 0:
op = f"重命名了 {renamed_count} 个文件在 {directory}"
config["history"].append(op)
if len(config["history"]) > 10:
config["history"].pop(0)
save_config(config)
return renamed_count完整脚本大约 200 行,包含配置管理、菜单交互、命令行解析、历史记录等功能。
使用方式汇总
| 场景 | 命令 |
|---|---|
| 交互式菜单 | python3 rename.py |
| 快速重命名(默认参数) | 菜单选1 |
| 自定义设置 | 菜单选2 |
| 命令行指定参数 | python3 rename.py -d ./photos -l 8 -p IMG_ |
| 模拟运行预览 | python3 rename.py -n |
| 强制运行不确认 | python3 rename.py -f |
| 仅字母命名 | python3 rename.py --charset letters |
| 仅数字命名 | python3 rename.py --charset digits |
| 自定义字符集 | python3 rename.py --charset custom --custom-chars "ABC123" |
设计思路
这个工具经历了四个版本的迭代,每次解决一个问题:
单行脚本 → 加安全去重 → 加命令行参数 → 加交互菜单 + 配置持久化核心设计原则:
- 先干活再优化:第一版能用就行,后面慢慢加功能
- 不改老功能:命令行参数和交互菜单可以同时存在,不冲突
- 配置可持久化:设置保存到 JSON 文件,重启不丢失
- 安全第一:模拟运行、确认提示、去重机制,一个都不能少
踩坑记录
| 坑 | 表现 | 解决 |
|---|---|---|
| 随机名重复 | 文件被覆盖 | 加 used_names 集合 |
| 脚本自身被改名 | 运行到一半脚本飞了 | 排除 file |
| os.chdir 后不返回 | 后续操作路径错乱 | 记录 original_dir 最后切回 |
| 配置文件损坏 | JSON 解析失败 | try/except + 默认配置合并 |
| 字符集为空 | generate 死循环 | 空字符集回退到 alnum |
一点感悟
一个简单的改名需求,从几十行代码慢慢长到了200多行。不是过度设计,而是每个功能都是实际使用中遇到的痛点。
如果只给自己用,第一版就够了。如果要给别人用、要反复用、要在不同场景用,交互菜单和配置文件就是刚需。这个度在哪里,取决于你打算用多少次、给多少人用。