#!/usr/bin/env python3
"""
批量重命名文件并保留原始扩展名。
用法:
python rename_keep_ext.py <目录路径> <旧文本> <新文本> [--dry-run]
示例:
将当前目录下所有文件名中的 "photo" 替换为 "image":
python rename_keep_ext.py . photo image
预览替换效果(不实际执行):
python rename_keep_ext.py . photo image --dry-run
"""
import os
import sys
import argparse
def parse_arguments():
"""解析命令行参数"""
parser = argparse.ArgumentParser(
description="批量重命名文件,仅修改文件名主体部分,保留原始扩展名。"
)
parser.add_argument(
"directory",
help="要处理的目录路径"
)
parser.add_argument(
"old_text",
help="要被替换的旧文本(区分大小写)"
)
parser.add_argument(
"new_text",
help="替换后的新文本"
)
parser.add_argument(
"--dry-run",
action="store_true",
help="预览模式:只显示将要发生的操作,不实际执行重命名"
)
return parser.parse_args()
def batch_rename(directory, old_text, new_text, dry_run=False):
"""
批量重命名目录中的文件。
规则:
- 只修改文件名的主干部分(不含扩展名)。
- 如果替换后的文件名与现有文件冲突,则跳过该文件并输出警告。
- 如果文件名中不包含 old_text,则跳过。
"""
if not os.path.isdir(directory):
print(f"错误:目录 '{directory}' 不存在或不是一个有效的目录。", file=sys.stderr)
sys.exit(1)
renamed_count = 0
skipped_count = 0
# 获取目录下所有文件(不包括子目录)
entries = os.listdir(directory)
files = [f for f in entries if os.path.isfile(os.path.join(directory, f))]
if not files:
print("目录中没有找到任何文件。")
return
print(f"在目录 '{directory}' 中查找包含 '{old_text}' 的文件...\n")
for filename in files:
# 分离文件名主干和扩展名
name_part, ext = os.path.splitext(filename)
# 如果主干中不包含旧文本,跳过
if old_text not in name_part:
continue
# 执行替换(区分大小写)
new_name_part = name_part.replace(old_text, new_text)
new_filename = new_name_part + ext # 保留原始扩展名
# 如果新文件名没有变化,跳过(理论上不会发生,因为 old_text 在 name_part 中)
if new_filename == filename:
continue
old_path = os.path.join(directory, filename)
new_path = os.path.join(directory, new_filename)
# 检查目标文件是否已存在(避免覆盖)
if os.path.exists(new_path):
print(f"⚠ 跳过:目标文件已存在 -> {new_filename} (源文件: {filename})")
skipped_count += 1
continue
if dry_run:
print(f"[预览] 将重命名: '{filename}' -> '{new_filename}'")
else:
try:
os.rename(old_path, new_path)
print(f"✔ 已重命名: '{filename}' -> '{new_filename}'")
renamed_count += 1
except OSError as e:
print(f"✖ 重命名失败: {filename} -> {new_filename},错误: {e}", file=sys.stderr)
skipped_count += 1
print(f"\n操作完成。")
print(f" 成功重命名: {renamed_count} 个文件")
if skipped_count > 0:
print(f" 跳过: {skipped_count} 个文件(冲突或错误)")
def main():
args = parse_arguments()
batch_rename(
directory=args.directory,
old_text=args.old_text,
new_text=args.new_text,
dry_run=args.dry_run
)
if __name__ == "__main__":
main()
使用说明
基本用法
将脚本保存为 rename_keep_ext.py,然后在终端运行:

python rename_keep_ext.py <目录路径> <旧文本> <新文本>
示例:将 /home/user/photos 目录下所有文件名中的 2024_ 替换为 2025_:
python rename_keep_ext.py /home/user/photos 2024_ 2025_
预览模式(安全测试)
添加 --dry-run 参数可以只显示将要进行的重命名操作,而不实际修改文件:
python rename_keep_ext.py /home/user/photos 2024_ 2025_ --dry-run
功能特点
- 保留扩展名:只修改文件名的主干部分(如
document.txt中的document) - 区分大小写:
Photo和photo被视为不同字符串 - 冲突检测:如果新文件名已存在,会自动跳过并提示
- 详细输出:显示每个文件的重命名结果或跳过原因
常见场景
| 场景 | 命令示例 |
|---|---|
| 替换日期前缀 | python rename_keep_ext.py . "2024_" "2025_" |
| 修改项目名称 | python rename_keep_ext.py ./docs "draft" "final" |
| 清理文件名 | python rename_keep_ext.py . " - Copy" "" |
| 批量添加后缀 | 注意:此脚本不支持直接添加,需配合其他方法 |
如果需要更复杂的模式匹配(如正则表达式),可以扩展脚本或使用专门的工具(如 rename 命令或 sed)。