Search code examples
python-3.xpython-3.6filenames

fnmatch does not display all filenames that match


I have a folder containing 5 files named respectively 'out1.jpg', 'out2a.jpg', 'out2b.jpg', 'out3.jpg' and 'out4.jpg' in addition to other files in different formats. I have this Python script which is supposed to print all the filenames that match:

import fnmatch
import os

c = 1
for file in os.listdir('.'):
    if fnmatch.fnmatch(file, 'out'+str(c)+'*.jpg'):
        print(file)
        c +=1

However, when I run this script,the output is limited to the following:

out1.jpg
out2a.jpg
out3.jpg

Anyone please has an idea how to change the script in order to display all the filenames that match (which are the 5 filenames that I mentioned)?


Solution

  • You are increasing c on each iteration (well, on each iteration that found a match but anyway...), so it cannot obviously match "out2a.jpg" AND "out2b.jpg". Assuming you want all file names that match "out" + some number + eventually something else, you can use character ranges instead; ie:

    for file in os.listdir('.'):
        if fnmatch.fnmatch(file, 'out[0-9]*.jpg'):
            print(file)
    

    NB : you might have to adjust the exact fnmatch pattern according to your needs and what you have in your directory.

    You can also use glob.glob instead, which is both simpler and (according to the doc) more efficient:

    import glob
    for file in glob("out[0-9]*.jpg"):
        print(file)
    

    EDIT :

    I totally understand why it does not display out2a.jpg and out2b.jpg together, but I didn't get why out4.jpg is not displayed!

    Quite simply because os.listdir() does not necessarily returns the filenames in the same order as you seemed to expect (on my linux station here, "out4.jpg" comes before the other "outXXX.jpg" files). You can inspect what's happening just by adding a couple prints:

    c = 1
    for file in os.listdir('.'):
        exp = 'out{}*.jpg'.format(c)
        print("file: {} - c : {} - exp : {}".format(file, c, exp))
        if fnmatch.fnmatch(file, exp):
            print(file)
            c +=1
    

    And the result here:

    file: sofnm.py~ - c : 1 - exp : out1*.jpg
    file: out4.jpg - c : 1 - exp : out1*.jpg
    file: out2b.jpg - c : 1 - exp : out1*.jpg
    file: out1.jpg - c : 1 - exp : out1*.jpg
    out1.jpg
    file: out2a.jpg - c : 2 - exp : out2*.jpg
    out2a.jpg
    file: sofnm.py - c : 3 - exp : out3*.jpg
    file: out42a.jpg - c : 3 - exp : out3*.jpg
    file: out3.jpg - c : 3 - exp : out3*.jpg
    out3.jpg
    

    As you can see, your assumption that os.listdir() would return the files in a given order (starting with "out1.jpg" and ending with "out4.jpg") was wrong. As a general rule, when your code don't behave as you expect, tracing the code execution (and the relevant values) is most often the simplest way to find out why.