Search code examples
pythonbatch-rename

Python: How to replace whitespaces by underscore in the name of ALL files, folders and subfolders?


How can we replace the whitespaces in the names of folders, subfolders and files in a given parent folder?

My initial attempt to replace up to level 8 is given below. I am sure there are better ways. My code looks ugly. Better solutions are more than welcome.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#


def replace_space_by_underscore(path):
    """Replace whitespace in filenames by underscore."""
    import glob
    import os
    for infile in glob.glob(path):
        new = infile.replace(" ", "_")
        try:
            new = new.replace(",", "_")
        except:
            pass
        try:
            new = new.replace("&", "_and_")
        except:
            pass
        try:
            new = new.replace("-", "_")
        except:
            pass
        if infile != new:
            print(infile, "==> ", new)
        os.rename(infile, new)

if __name__ == "__main__":
    try:
        replace_space_by_underscore('*/*/*/*/*/*/*/*')
    except:
        pass
    try:
        replace_space_by_underscore('*/*/*/*/*/*/*')
    except:
        pass
    try:
        replace_space_by_underscore('*/*/*/*/*/*')
    except:
        pass
    try:
        replace_space_by_underscore('*/*/*/*/*')
    except:
        pass
    try:
        replace_space_by_underscore('*/*/*/*')
    except:
        pass
    try:
        replace_space_by_underscore('*/*/*')
    except:
        pass
    try:
        replace_space_by_underscore('*/*')
    except:
        replace_space_by_underscore('*')

Solution

  • You could use os.walk that allows you to change the names of the iterated folders on the fly:

    import os
    
    def replace(parent):
        for path, folders, files in os.walk(parent):
            for f in files:
                os.rename(os.path.join(path, f), os.path.join(path, f.replace(' ', '_')))
            for i in range(len(folders)):
                new_name = folders[i].replace(' ', '_')
                os.rename(os.path.join(path, folders[i]), os.path.join(path, new_name))
                folders[i] = new_name
    

    os.walk iterates directory tree starting from parent in top-down order. For every folder it returns tuple (current path, list of files, list of folders). Given folder list can be mutated and os.walk will use the mutated contents in the following steps of the iteration.

    Folder before run:

    .
    ├── new doc
    └── sub folder
        ├── another folder
        ├── norename
        └── space here
    

    After:

    .
    ├── new_doc
    └── sub_folder
        ├── another_folder
        ├── norename
        └── space_here