1

I have directory where multiple folders exist and within each folder,a file exist inside another folder. Below is the structure

C:\users\TPCL\New\20190919_xz.txt
C:\users\TPCH\New\20190919_abc.txt

Objective:

I want to rename the file names like below:

C:\users\TPCL\New\20190919_xz_TPCL.txt
C:\users\TPCH\New\20190919_abc_TPCH.txt

My Approach:

for root,dirs,filename in os.walk('C\users\TPCL\New'):
     prefix = os.path.basename(root)
     for f in filename:
         os.rename(os.path.join(root,f),os.path.join(root,"{}_{}".format(f,prefix)))

The above approach is yielding the following result:

C:\users\TPCL\New\20190919_xz_New.txt
C:\users\TPCH\New\20190919_abc_New.txt

So the question is: How to get the grand-parent folder name get appended, instead of parent folder name?

martineau
  • 119,623
  • 25
  • 170
  • 301
pythondumb
  • 1,187
  • 1
  • 15
  • 30

3 Answers3

1

You need to use both dirname and basename to do this.

Use os.path.dirname to get the directory name (excluding the last part) and
then use os.path.basename to get the last part of the pathname.

Replace prefix = os.path.basename(root)

with

os.path.basename(os.path.dirname(root))

Please refer this:
https://docs.python.org/3.7/library/os.path.html#os.path.basename https://docs.python.org/3.7/library/os.path.html#os.path.dirname

Bhawan
  • 2,441
  • 3
  • 22
  • 47
1

Using PurePath from pathlib you can get the parts of the path. If the path contains the filename its grand-parent folder will be at index -3.

In [23]: from pathlib import PurePath

In [24]: p = r'C:\users\TPCL\New\20190919_xz_TPCL.txt'

In [25]: g = PurePath(p)

In [26]: g.parts
Out[26]: ('C:\\', 'users', 'TPCL', 'New', '20190919_xz_TPCL.txt')

In [27]: g.parts[-3]
Out[27]: 'TPCL'

If the path does not contain the filename the grand=parent would be at index -2.


Your process would look something like this:

import os.path
from pathlib import PurePath

for root,dirs,fnames in os.walk(topdirectory):
    #print(root)
    try:
        addition = PurePath(root).parts[-2]
        for name in fnames:
            n,ext = os.path.splitext(name)
            newname = n + '_' + addition + ext
            print(name, os.path.join(root,newname))
    except IndexError:
        pass

I added the try/except to filter out paths that don't have grand-parents - it isn't necessary if you know it isn't needed.

wwii
  • 23,232
  • 7
  • 37
  • 77
  • How can I use this for a list of paths? Eg. lets assume `p` is a list of 3 different filepaths. – pythondumb Sep 22 '19 at 17:20
  • Basically you just iterate over the list; make a `PurePath` of each; get/extract the `-3` index of the `PurePath` parts. – wwii Sep 22 '19 at 17:34
  • Thats fine. Infact I tried the same. However, I am not able to apply `g.parts()` then. It shows error as `list object has no attribute 'parts'` similar like this. – pythondumb Sep 23 '19 at 01:29
0

You can split the path string using '\' and then count back to what would be considered the grandparent directory for any given file and then append it. For example, if you have

filename = "dir1\dir2\file.txt"
splitPaths = filename.split('\') // gives you ['dir1', 'dir2', 'file.txt'] 

the last entry is the file name, the second to last is the parent, and the third to last is the grandparent and so on. You can then append whichever directory you want to the end of the string.

ThinkDigital
  • 3,189
  • 4
  • 26
  • 34