How to change part of files names using Sys and Subprocess modules and Linux Bash

Viewed 3046

I have Python script which reads files names from oldFiles.txt, iterate through files names which are files in a Linux directory, then update the files names using string.replace and finally run a subprocess to find those files (let's say in home directory to make the explanation and demo easier) and change their names using

subprocess.run(['mv', 'oldfile', 'newfile')]

Let's suppose I have files names with string "jane" and I want to replace it with "jdoe", a file's name example would be: abcd_jane.csv modified into abcd_jdoe.csv

The sys.argv[1] is the argument which will be passed like the follow

./changeJane.py oldFiles.txt

I am using those empty files for local training, their names are saved in oldFiles.txt

sdafsdfs_jane.doc 12fgdf-jane.csv files_jane.txt

Iterating and updating files names in oldFiles.txt is ok or maybe there is some mistakes also :-( but I still couldn't figure out how to run the subprocess to achieve my goal like described above. This is what I came in, thank you very much.

PS: I am forced to use sys and subprocess modules, and also forced to apply all the mentioned details, its a homework assessment.

#!/usr/bin/env python3
import sys
import subprocess
with open(sys.argv[1], 'r+') as f:
  for line in f.readlines():
    newline = line.strip()
    newtext = newline.replace("jane", "jdoe")
    subprocess.run(['mv', '~/newline', '~/newtext']) #I know its wrong but this is my limit!

UPDATE

I modified the script to return list and comfortably iterate through its items, the script is successful but it is doing one iteration only which means it is applying only the first file name or the first iteration, any ideas to do all the iterations and finish the job. Thank you very much!!

#!/usr/bin/env python3
import sys
import subprocess
with open(sys.argv[1], 'r') as f:
    content1 = f.readlines()
    content2 = [x.strip() for x in content1]
    content3 = [item.replace("jane", "jdoe") for item in content2]
    for x in content2:
      for i in content3:
        subprocess.run(['mv', '/home/ninja-coder/'+x, '/home/ninja-coder/'+i])
7 Answers

Your first code is simpler and you are almost right! The reason that you don't get the required output in the first code is because you haven't added the full path to mv command

#!/usr/bin/env python3
import sys
import subprocess
f= open (sys.argv[1],"r")
path='/home/<username>'
for line in f.readlines():
 old_name = line.strip()
 new_name = old_name.replace("jane","jdoe")
 subprocess.run(["mv",path+old_name,path+new_name])
f.close()

This worked for me!

Thanks to @Jonatã and @HackLab for their hints. After several trials I solved this very annoying assessment but I learned lots of things, again, one of the crucial success's secrets is PRACTICE, here is the final code

#!/usr/bin/env python3
import sys
import subprocess
with open(sys.argv[1], 'r') as f:
    content1 = f.readlines()
    content2 = [x.strip() for x in content1]
    content3 = [item.replace("jane", "jdoe") for item in content2]
    res = dict(zip(content2, content3))
    for key, value in res.items():
        subprocess.run(['mv', '/home/ninja-coder/'+key, '/home/ninja-coder/'+value])

Using nested loops is not a good practice here and would not work for the purpose. It is easier to use zip than dictionaries

import sys
import subprocess

from pathlib import Path
with open (sys.argv[1], "r") as f:
    data=[ x.strip() for x in  f.readlines()]
    datanew=[x.replace("jane","jdoe") for x in data]
    for k, t in zip( data,datanew):
      subprocess.run(["mv",'<add path>'+k,'<add path>/+t'])
f.close()

Using a subprocess to rename a file is too costly and too much work for you. Rename the file with the tools that Python itself offers to you. Also, you don't need to open the file for writing and you can iterate over the file just refering to the file:

#!/usr/bin/env python3

import sys
import subprocess

with open(sys.argv[1], 'r') as f:
  for line in f:
    newline = line.strip()
    newtext = newline.replace("jane", "jdoe")
    os.rename(newline, newtext)

I am not sure why you want to open a file if you want to change the filename. I think you want to iterate over all files in a directory for that you need os.listdir() https://www.tutorialspoint.com/python/os_listdir.html

import os

path = "./"

for filename in os.listdir(path):
    newFilename = filename.replace("jane", "jdoe")
    os.rename(path + filename, path + newFilename)

as @Poshi pointed out no need for subprocess os.rename should do it https://www.tutorialspoint.com/python/os_rename.htm

If you really want to use subprocess

subprocess.run(['mv', path + filename, path + newFilename])

UPDATE

Here now the complete solution I hope that makes it clearer.

#!/usr/bin/env python3
import sys
import subprocess
with open(sys.argv[1], 'r') as f:
    for filename in f.readlines():
        newFilename = filename[:-1].strip().replace("jane", "jdoe")
        subprocess.run(['mv', "~/" + filename[:-1], "~/" + newFilename])

I used your code for last part of the assignment(Rename files using Python script) but does not work. Any suggestions on this ?

I used the following but does not work=>

subprocess.run(['mv', '/home/username/'+key, '/home/username/'+value])

#!/usr/bin/env python3

import sys
import subprocess
impotr os

with open(sys.argv[1], 'r') as f:
    for line in f:
        newline = line.strip()
        newtext = newline.replace("jane", "jdoe")
        os.rename(newline, newtext)
Related