When working with files and file systems, it is common to search through many files to discover a certain file. Finding the necessary files from many files will take an eternity if done manually. As a result, operating systems and programming languages include facilities for dynamically locating necessary files. These utilities usually target filenames and use pattern matching to try to locate the relevant files.
The fnmatch library in the Python programming language can be used to locate files in UNIX-based operating systems like macOS and Linux. This article uses the fnmatch module in Python to do pattern matching.
What is fnmatch?
It is a common Python package for matching wildcards like those used in Unix shells. If a single file name matches a pattern, fnmatch() returns TRUE; otherwise, it returns FALSE.
Functions provided by the fnmatch module
The fnmatch module contains the functions fnmatch(), fnmatchcase(), filter(), and translate(). Example programs that demonstrate each function in depth can be found below.
Example 1:
This is the first of several examples in our article about the fnmatch() method. If the given name of the file matches the pattern string, the executed fnmatch() method returns a boolean value. If the operating system is case-insensitive, the comparison will take place after both parameters have been normalized to all lower-case and upper-case characters.
Here’s a program; first, we have imported the fnmatch and the os module. After that, we look for all files that begin with ‘fnmatch’ and end with ‘.py’. Finally, print the result, as you can see in the last line of code.
import os
patrn = 'fnmatch_*.py'
print ('The Pattern is ', patrn )
print()
file_name = os.listdir('.')
for name in file_name:
print ('Name of the File: %-25s %s' % (name, fnmatch.fnmatch(name, patrn)))
Here in the output, you can see that the pattern and the files that match the pattern are listed.
Example 2:
One more example elaborates the fnmatch function. This function requires the file name and a character string pattern. The name of the file is compared to the pattern, and the method returns True or False.
In the example below, we have imported the glob and fnmatch modules that are required for this program to execute. After that, we’ve compiled a list of all files present in the current directory that fit the “*.py” pattern.
for files_names in (glob.glob('*.*')):
if (fnmatch.fnmatch(files_names, "*.py")):
print(files_names)
Below you can find out that the files that match the pattern are successfully retrieved and listed.
Example 3:
Now, we will discuss the fnmatchcase() function of fnmatch. If the filename string matches the defined pattern string, this function performs a comparison (case-sensitive in this scenario) and returns a boolean value. The value is either True or False. Regardless of the filesystem or operating system settings, you can find program code for a case-sensitive comparison here.
After importing the fnmatch and os module, we have defined the pattern (indicated as patrn in the code) on which our search is based. Then we have listed down all the files and the Boolean values if the file matches the pattern.
import os
patrn = 'FNMATCH_*.PY'
print ('Pattern :', patrn)
print()
file_name= os.listdir('.')
for name in file_name:
(print ('Name of the File: %-25s %s' % (name, fnmatch.fnmatchcase(name, patrn))))
Below you can find the output, and as you can see that all files return false.
Example 4:
In another example of fnmatchcase mentioned below, all files starting with the letter ‘h’ and the extension ‘.py’ are first gathered in a files list object. The fnmatch() method is used to output only names that begin with the letters ‘h.’
files=glob.glob("h*.*")
files
['data.txt', 'demo.txt', 'history.py', 'history_internal.py', 'new_file.txt', 'pdb_history.sqlite',]
for file in files:
if fnmatch.fnmatchcase(file,"h*.*")==True:
print(file)
Below, the files history.py and history_internal.py are displayed in the screenshot as they match the defined pattern.
Example 5:
Now we’ll talk about the fnmatch module’s filter function. This method returns the subset of the list of names that exactly match the provided pattern from the given names. Here you can easily filter files by not only one but many file extensions. Examine the code below.
Here we have imported the required modules first and defined the pattern. After that, list down all the files that match the criteria.
import os
patrn = 'fnmatch_*.py'
print ('Pattern is :', patrn )
file_name = os.listdir('.')
print ('Files are mentioned here:', file_name)
print ('Matches found:', fnmatch.filter(file_name, patrn))
Here, you can observe that the pattern is displayed first, and then the files are fetched and displayed. Lastly, the matches are displayed if found. In our case, no match is found.
Example 6:
Another program elaborates the filter function. Here only those files whose names match the pattern parameter are returned by this function. Out of all files in the current directory, the following statement gives a list of files with the ‘.txt’ extension.
files = ['data.txt', 'demo.txt', 'history.py', 'history_internal.py', 'new_file.txt', 'pdb_history.sqlite',]
print(fnmatch.filter(files,"*.txt"))
Here are the names of the files with the ‘.txt’ extension.
Example 7:
The translate() function of the fnmatch module is demonstrated in this example. This function converts a shell-style pattern to a regular expression that may be used with re.match() (re.match() only matches at the beginning of the text, not each line). We’ve imported the fnmatch and re modules, as you can see in the code below. The pattern was then transformed to a regular expression using the translate() method.
reg_exp = fnmatch.translate('*.txt')
re_obj = re.compile(reg_exp)
print(reg_exp)
print(re_obj.match('demo.txt'))
Here you can see the output of the above-executed translate() method code program.
Example 8:
Here is another example of the same function discussed above. After importing the required modules, we have executed the translate function in which we have passed the pattern that we have defined in the above line of code. The return value of the function is then transformed into a regular expression using the re module’s compile() function. After that, it’s used to match the given pattern.
import fnmatch
import glob
patrn ="*.txt"
reg_exp=fnmatch.translate(patrn)
reg_exp
'(?s:.*\\.txt)\\Z'
res=re.compile(reg_exp)
for file_name in glob.glob("*.*"):
if re.match(res,file_name):
print (file_name)
Here is the result when we have executed the above program.
Conclusion:
The fnmatch() function can match between a simple string method and a complex regular expression. It is usually a reasonable scheme when only a simple wildcard is required to process data. We have elaborated several examples to cover this topic in detail.