Iteratively (or recursively?) filter directory and copy results to new directory

I’m new to Python and have been teaching myself with textbooks and StackOverflow. I seem to learn best from real world examples from this site. I’m hoping someone can help me with my current problem.

I have a directory (folder) with about 1,000 files. The files have names with prefixes (patterns) such as, aaa_*, bbb_*, ccc_* and so on. I would like to iterate through the directory and copy all the files that have the specified prefix and move them to a new directory with that prefix name. For example, find all the aaa_* files in /my_dir_path and copy them to /my_new_dir_path/aaa and likewise all the bbb_* to /my_new_dir_path/bbb. The new directories have already been created.

The following simple, boilerplate, script works for copying one of the prefix patterns to a new directory:

dir = '/my_dir_path'
pattern = 'aaa_*'
dest = '/my_new_dir_path/aaa'

for root, dirs, files in os.walk(dir):
    for filename in fnmatch.filter(files, pattern):
        source = (os.path.join(root, filename))
        shutil.copy2(source, dest)

What I’m struggling with is how to recursively run fnmatch.filter for my list of patterns and then, ultimately, output the files to their own directory.

I have tried writing a number of different function definitions with the list of patterns as *args, but would typically get an error message that “filter() takes exactly 2 arguments (3 given)”. (I apologize for not having code examples to show you here. I’ve been through so many versions in the last few days that I don’t have any one representative function definition.)

I’m such a novice that I don’t know if fnmatch.filter can even be made recursive or how to devise an alternative strategy. Then, there is the problem of how to store the resulting files from each pattern search into its own directory. I was thinking that I could create a dictionary in advance, e.g.,

my_dict = {'my_new_dir_path/aaa': 'aaa_*', 'my_new_dir_path/bbb': 'bbb_*'}

and store the resulting files as values under the appropriate key, but given that I haven’t even gotten the recursion to work (i.e., print) I haven’t worked on how to copy the results to a new directory.


Now I haven’t tested this since I don’t have all of the files to test with. However, I would just make the “pattern” variable a list and add another for loop. I also changed the “dest” variable so we can just utilize the “patterns” list.

import os
import shutil
import fnmatch

dir = '/my_dir_path'
patterns = ['aaa', 'bbb', 'ccc']
dest = '/my_new_dir_path/'

for root, dirs, files in os.walk(dir):
    for pattern in patterns:
        for filename in fnmatch.filter(files, pattern+'_*'):
            source = (os.path.join(root, filename))
            shutil.copy2(source, dest+pattern+'/')