🌗 ← Índice
Data: 14/08/2026
Nível: Projeto (Mês 3 — Projetos Reais)
python renomeador.py /tmp/fotos --prefixo "viagem_"
# IMG_001.jpg → viagem_IMG_001.jpg
python renomeador.py /tmp/docs --substituir "antigo" "novo"
# relatorio_antigo.pdf → relatorio_novo.pdf
python renomeador.py /tmp/backups --numerar
# backup.tar.gz → backup_01.tar.gz, backup_02.tar.gz...
python renomeador.py /tmp/docs --substituir "antigo" "novo" --seco
# [simulado] relatorio_antigo.pdf → relatorio_novo.pdf
renomeador/
├── renomeador.py # CLI principal
└── test_renomeador.py # testes
import argparse
import re
from pathlib import Path
def aplicar_regras(nome_original: str, args) -> str:
"""Aplica prefixo/sufixo/substituição ao nome (sem extensão)."""
caminho = Path(nome_original)
stem, ext = caminho.stem, caminho.suffix
if args.substituir:
antigo, novo = args.substituir
stem = stem.replace(antigo, novo)
if args.regex:
padrao, novo = args.regex
stem = re.sub(padrao, novo, stem)
if args.prefixo:
stem = f"{args.prefixo}{stem}"
if args.sufixo:
stem = f"{stem}{args.sufixo}"
return f"{stem}{ext}"
def numerar(arquivos: list[Path], digitos=2) -> dict[Path, Path]:
"""Mapeia nome original → nome numerado."""
mapeamento = {}
for i, arquivo in enumerate(arquivos, start=1):
novo = arquivo.with_name(f"{arquivo.stem}_{i:0{digitos}d}{arquivo.suffix}")
mapeamento[arquivo] = novo
return mapeamento
def main():
parser = argparse.ArgumentParser(description="Renomeador de arquivos em massa")
parser.add_argument("pasta", type=Path, help="Pasta com os arquivos")
parser.add_argument("--prefixo", default=None, help="Prefixo a adicionar")
parser.add_argument("--sufixo", default=None, help="Sufixo a adicionar")
parser.add_argument("--substituir", nargs=2, metavar=("ANTIGO", "NOVO"), help="Substitui texto")
parser.add_argument("--regex", nargs=2, metavar=("PADRAO", "NOVO"), help="Substitui via regex")
parser.add_argument("--numerar", action="store_true", help="Numera os arquivos")
parser.add_argument("--seco", action="store_true", help="Simula sem renomear")
parser.add_argument("--extensao", default=None, help="Filtra por extensão (ex: jpg)")
args = parser.parse_args()
if not args.pasta.is_dir():
parser.error(f"Pasta não encontrada: {args.pasta}")
if not any([args.prefixo, args.sufixo, args.substituir, args.regex, args.numerar]):
parser.error("Informe pelo menos uma regra (--prefixo, --sufixo, --substituir, --regex, --numerar)")
arquivos = [p for p in args.pasta.iterdir() if p.is_file()]
if args.extensao:
arquivos = [p for p in arquivos if p.suffix.lower() == f".{args.extensao.lower()}"]
if args.numerar:
mapeamento = numerar(arquivos)
else:
mapeamento = {p: p.with_name(aplicar_regras(p.name, args)) for p in arquivos}
alterados = 0
for origem, destino in mapeamento.items():
if origem == destino:
continue
if args.seco:
print(f"[simulado] {origem.name} → {destino.name}")
else:
origem.rename(destino)
print(f"{origem.name} → {destino.name}")
alterados += 1
print(f"\nTotal: {alterados} arquivo(s) {'(simulado)' if args.seco else 'renomeado(s)'}")
if __name__ == "__main__":
main()
import pytest
from renomeador import aplicar_regras, numerar
from pathlib import Path
class Args:
substituir = ("antigo", "novo")
regex = None
prefixo = None
sufixo = None
def test_substituir_texto():
args = Args()
assert aplicar_regras("relatorio_antigo.pdf", args) == "relatorio_novo.pdf"
def test_prefixo():
args = Args()
args.substituir = None
args.prefixo = "viagem_"
assert aplicar_regras("IMG_001.jpg", args) == "viagem_IMG_001.jpg"
def test_regex():
args = Args()
args.substituir = None
args.regex = (r"\d+", "NUM")
assert aplicar_regras("foto_123.jpg", args) == "foto_NUM.jpg"
def test_numerar():
arquivos = [Path(f"/tmp/backup_{i}.tar.gz") for i in range(1, 4)]
mapeamento = numerar(arquivos)
nomes = [str(p) for p in mapeamento.values()]
assert "backup_1_01.tar.gz" in nomes
assert len(mapeamento) == 3
Adicione a opção --data que prefixa os arquivos com a data atual (YYYY-MM-DD_). Combine com --numerar para backups diários numerados:
python renomeador.py /tmp/backups --data --numerar
# dados.sql → 2026-08-14_dados_01.sql
# no main(), adicione:
parser.add_argument("--data", action="store_true", help="Prefixa com a data atual")
# e na montagem do nome:
from datetime import datetime
if args.data:
args.prefixo = f"{datetime.now().strftime('%Y-%m-%d')}_{args.prefixo or ''}"
💡 Resultado: dados.sql → 2026-08-14_dados.sql — padrão ideal para backups diários automáticos (combine com cron!).
HB Estudos · ← Voltar ao índice de Python