Home > OS >  str.replace and os.rename doesn't work with file names containing "/"
str.replace and os.rename doesn't work with file names containing "/"

Time:10-25

I want to replace a single character on a bunch of file names with another character. However, when I want to replace files with / to another character, it doesn't work. It does work with other characters I want to replace, such as -.

The python file is on the directory path, and I 'cd' to the directory path to run the program.

I expect that every / on a file name would be replaced with a _. Like this: file/1.txt to file_1.txt.

However, the files stay the same. Like this: file/1.txt to file/1.txt.

I use this code:

# Replace a character of a name file with another charater
from importlib.metadata import files
import os

counter = 0
path = r"/Users/user/test"
char = input('Enter character or string you want to replace:')
repl = input('Enter character or string you want this to be replaced with:')
files = []

# Loop, doesn't work with "/" for some reason
for file_name in os.listdir(path):
    if char in file_name :
        old_name = file_name
        new_name = file_name.replace(char, repl)
        counter  = 1
        files.append(new_name)
        os.rename(old_name, new_name)
print(counter)
print(files)
print("Done! Check your files")

As an alternative, I deleted the variables char and repl and instead used this in the for loop, but it still doesn't work:

for file_name in os.listdir(path):
    if "/" in file_name :
        old_name = file_name
        new_name = file_name.replace("/", "_")
        counter  = 1

CodePudding user response:

I'd use pathlib which is much more clean and convenient that using os module.

from pathlib import Path

base_folder = Path(r"/Users/user/test")

old_names = [f for f in base_folder.glob('*') if f.is_file()]
new_names = [f'{f.parts[-2]}_{f.name}' for f in old_names]

for o_name, n_name in zip(old_names, new_names):
    o_name.with_name(n_name)

You first create a list of file paths for all the files in the folder.

Then the second list comprehension goes through a list of files and for each file grabs its parent folder name and the file name and combines them in an f-string with _ in between.

Now, finally you go through the old and new file names and assign a new name to each of the original files.

EDIT: If you want to exclude hidden files you need to amend the first comprehension to exclude files that start with a .:

old_names = [f for f in base_folder.glob('*.txt') 
             if not any(part.startswith('.') for part in f.parts) and f.is_file()]

CodePudding user response:

I managed to solve it with this.

# Replace a character of a file with another charater
from importlib.metadata import files
import os
counter = 0
path=input("Enter path: ")
char=input('Enter character or string you want to replace:')
repl=input('Enter character or string you want this to be replaced with:')
files=[]

# Ignore hidden files
def listdir_nohidden(path):
    for f in os.listdir(path):
        if not f.startswith('.'):
            yield f

# Loop, instead of "/" use ":"
for file_name in listdir_nohidden(path):
    if char in file_name :
        old_name=file_name
        new_name=file_name.replace(char,repl)
        counter =1
        files.append(new_name)
        os.rename(old_name,new_name)
print(counter)
print(files)
print("Done! Check your files")

Files change like this: test/1.txt --> test_1.txt The problem was that for some reason, when I debug with print(file_name), files with "/" show ":" instead. The other problem, were the hidden files, which I solved above.

  • Related