Cambie el nombre de varios archivos en un directorio en Python


Answers

Aquí hay una secuencia de comandos basada en su último comentario.

#!/usr/bin/env python
from os import rename, listdir

badprefix = "cheese_"
fnames = listdir('.')

for fname in fnames:
    if fname.startswith(badprefix*2):
        rename(fname, fname.replace(badprefix, '', 1))
Question

Esta pregunta ya tiene una respuesta aquí:

Estoy intentando cambiar el nombre de algunos archivos en un directorio usando Python.

Supongamos que tengo un archivo llamado CHEESE_CHEESE_TYPE.*** y quiero eliminar CHEESE_ por lo que mi nombre de archivo resultante sería CHEESE_TYPE

Estoy tratando de usar os.path.split pero no funciona correctamente. También he considerado usar manipulaciones de cadenas, pero tampoco he tenido éxito con eso.




Originalmente estaba buscando alguna GUI que permitiera cambiar el nombre usando expresiones regulares y que tenía una vista previa del resultado antes de aplicar los cambios.

En Linux he utilizado krename con éxito, en Windows Total Commander cambia el nombre con expresiones regulares, pero no encontré un equivalente libre decente para OSX, así que terminé escribiendo un script de python que funciona recursivamente y de forma predeterminada solo imprime los nuevos nombres de archivo sin hacer ningún cambios. Agregue el modificador '-w' para realmente modificar los nombres de los archivos.

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import fnmatch
import sys
import shutil
import re


def usage():
    print """
Usage:
        %s <work_dir> <search_regex> <replace_regex> [-w|--write]

        By default no changes are made, add '-w' or '--write' as last arg to actually rename files
        after you have previewed the result.
        """ % (os.path.basename(sys.argv[0]))


def rename_files(directory, search_pattern, replace_pattern, write_changes=False):

    pattern_old = re.compile(search_pattern)

    for path, dirs, files in os.walk(os.path.abspath(directory)):

        for filename in fnmatch.filter(files, "*.*"):

            if pattern_old.findall(filename):
                new_name = pattern_old.sub(replace_pattern, filename)

                filepath_old = os.path.join(path, filename)
                filepath_new = os.path.join(path, new_name)

                if not filepath_new:
                    print 'Replacement regex {} returns empty value! Skipping'.format(replace_pattern)
                    continue

                print new_name

                if write_changes:
                    shutil.move(filepath_old, filepath_new)
            else:
                print 'Name [{}] does not match search regex [{}]'.format(filename, search_pattern)

if __name__ == '__main__':
    if len(sys.argv) < 4:
        usage()
        sys.exit(-1)

    work_dir = sys.argv[1]
    search_regex = sys.argv[2]
    replace_regex = sys.argv[3]
    write_changes = (len(sys.argv) > 4) and sys.argv[4].lower() in ['--write', '-w']
    rename_files(work_dir, search_regex, replace_regex, write_changes)

Ejemplo de caso de uso

Quiero voltear partes de un nombre de archivo de la siguiente manera, es decir, mover el bit m7-08 al comienzo del nombre del archivo:

# Before:
Summary-building-mobile-apps-ionic-framework-angularjs-m7-08.mp4

# After:
m7-08_Summary-building-mobile-apps-ionic-framework-angularjs.mp4

Esto realizará una ejecución en seco e imprimirá los nuevos nombres de archivo sin cambiar el nombre de ningún archivo:

rename_files_regex.py . "([^\.]+?)-(m\\d+-\\d+)" "\\2_\\1"

Esto hará el cambio de nombre real (puede usar ya sea -w o --write ):

rename_files_regex.py . "([^\.]+?)-(m\\d+-\\d+)" "\\2_\\1" --write



Aquí hay una solución más general:

Este código se puede usar para eliminar cualquier carácter o conjunto de caracteres de forma recursiva de todos los nombres de archivo dentro de un directorio y reemplazarlos por cualquier otro carácter, conjunto de caracteres o ningún carácter.

import os

paths = (os.path.join(root, filename)
        for root, _, filenames in os.walk('C:\FolderName')
        for filename in filenames)

for path in paths:
    # the '#' in the example below will be replaced by the '-' in the filenames in the directory
    newname = path.replace('#', '-')
    if newname != path:
        os.rename(path, newname)



Tengo el mismo problema, donde quiero reemplazar el espacio en blanco en cualquier archivo pdf a un guion - . Pero los archivos estaban en múltiples subdirectorios. Entonces, tuve que usar os.walk() . En su caso para múltiples subdirectorios, podría ser algo como esto:

import os
for dpath, dnames, fnames in os.walk('/path/to/directory'):
    for f in fnames:
        os.chdir(dpath)
        if f.startswith('cheese_'):
            os.rename(f, f.replace('cheese_', ''))



El siguiente código debería funcionar. Toma todos los nombres de archivo en el directorio actual, si el nombre de archivo contiene el patrón CHEESE_CHEESE_ , se renombra. Si no, no se hace nada con el nombre del archivo.

import os
for fileName in os.listdir("."):
    os.rename(fileName, fileName.replace("CHEESE_CHEESE_", "CHEESE_"))



Parece que su problema está más en la determinación del nuevo nombre de archivo que en el cambio de nombre (para lo cual podría usar el método os.rename).

No está claro a partir de su pregunta cuál es el patrón que desea cambiar de nombre. No hay nada de malo con la manipulación de cuerdas. Una expresión regular puede ser lo que necesita aquí.




importar cadena de importación os def rename_files ():

#List all files in the directory
file_list = os.listdir("/Users/tedfuller/Desktop/prank/")
print(file_list)

#Change current working directory and print out it's location
working_location = os.chdir("/Users/tedfuller/Desktop/prank/")
working_location = os.getcwd()
print(working_location)

#Rename all the files in that directory
for file_name in file_list:
    os.rename(file_name, file_name.translate(str.maketrans("","",string.digits)))

rename_files ()