批量重命名工具进化史:从单行命令到交互式菜单的完整实现

需求

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"

设计思路

这个工具经历了四个版本的迭代,每次解决一个问题:

单行脚本 → 加安全去重 → 加命令行参数 → 加交互菜单 + 配置持久化

核心设计原则:

  1. 先干活再优化:第一版能用就行,后面慢慢加功能
  2. 不改老功能:命令行参数和交互菜单可以同时存在,不冲突
  3. 配置可持久化:设置保存到 JSON 文件,重启不丢失
  4. 安全第一:模拟运行、确认提示、去重机制,一个都不能少

踩坑记录

表现解决
随机名重复文件被覆盖加 used_names 集合
脚本自身被改名运行到一半脚本飞了排除 file
os.chdir 后不返回后续操作路径错乱记录 original_dir 最后切回
配置文件损坏JSON 解析失败try/except + 默认配置合并
字符集为空generate 死循环空字符集回退到 alnum

一点感悟

一个简单的改名需求,从几十行代码慢慢长到了200多行。不是过度设计,而是每个功能都是实际使用中遇到的痛点。

如果只给自己用,第一版就够了。如果要给别人用、要反复用、要在不同场景用,交互菜单和配置文件就是刚需。这个度在哪里,取决于你打算用多少次、给多少人用。

Last modification:May 22nd, 2026 at 01:40 am
如果觉得我的文章对你有用,请随意赞赏