Search code examples
pythonglob

Print what subfolder is empty in all folders that contain the same subfolder?


I have a folder A like this:

A>>(B,C,D)(subfolders)>>both B,C and D have folders 1,2,3 each.

in this case the subfolder '3' out of B,C and D happens to be empty.

How do you check and print which folder happens to be empty in all the folders for example to make it search and print the number '3' since it is the only subfolder that is empty in all of the folders B,C and D?

Code I tried:

for i in glob.iglob('**/Desktop/A/**' ,recursive = True):
    if not os.listdir(i):
        print(f'{i} is empty everywhere' + '\n')

which isn't working.

All folders have the same subfolders (name) but some of them are empty. I need to find which are empty in all of those folders and print it.


Solution

  • We need two functions from the os module

    from os import walk
    from os.path import join
    

    We need a starting point

    dir = '/your/top/directory'
    

    walk returns a generator, iterating on it at each step we have the path of the current directory, the list of directories and the list of files BUT we don't want to iterate and are interested only in the list of directories in the current directory, hence

    dirs_l1 = next(walk(dir))[1]
    

    note that, having to deal with a generator, the above is not too wasteful...

    Now we have an inner loop on the subdirectories of level 1 (l1 sd, the sd contained in the root) to create a list of sets of directories of level 2, to be unpacked and passed to set.intersection, so that in dirs_l2 we eventually have a set of all the directories of level 2 that are present in every directory of level 1

    dirs_l2 = set.intersection(*[set(next(walk(join(dir, d)))[1]) for d in dirs_l1])
    

    We make a loop on these inner directories, present in every l1 sd, and using the all builtin we check that, for every l1 sd all the l2 sd are empty, in that case we print the name of the l2 subdirectory that is always empty

    for d2 in dirs_l2:
        if all(next(walk(join(dir, d1, d2)))[1:] == ([],[]) for d1 in dirs_l1):
            print(d2)
    

    An example

    $ cat A.py
    from os import walk
    from os.path import join
    dir = './A'
    dirs_l1 = next(walk(dir))[1]
    dirs_l2 = set.intersection(*[set(next(walk(join(dir, d)))[1]) for d in dirs_l1])
    for d2 in dirs_l2:
        if all(next(walk(join(dir, d1, d2)))[1:] == ([], []) for d1 in dirs_l1): print(d2)
    $ tree A
    A
    ├── A
    │   ├── 1
    │   │   └── a
    │   ├── 2
    │   │   └── b
    │   └── 3
    ├── B
    │   ├── 1
    │   │   └── a
    │   ├── 2
    │   │   └── b
    │   └── 3
    ├── C
    │   ├── 1
    │   │   └── a
    │   ├── 2
    │   │   └── b
    │   └── 3
    └── D
        ├── 1
        │   └── a
        ├── 2
        │   └── b
        └── 3
    $ python A.py 
    3
    $