$ python file_glob.py f[!2-5]*xt
I was browsing the Python standard library (got to use those batteries!) and thought of writing this simple utility - a command-line directory lister that supports multiple wildcard filename arguments, like *, ?, etc. - as the OS shells bash on Unix and CMD on Windows do. It uses the glob function from the glob module. The Python documentation for glob says:
[ No tilde expansion is done, but *, ?, and character ranges expressed with [] will be correctly matched. This is done by using the os.listdir() and fnmatch.fnmatch() functions in concert. ]
Note: no environment variable expansion is done either, but see os.path.expanduser() and os.path.expandvars() in the stdlib.
I actually wrote this program just to try out glob (and fnmatch before it), not to make a production or even throwaway tool, but it turns out that, due to the functionality of glob(), even this simple program is somewhat useful, as the examples of its use below show, particularly with multiple arguments, etc.
Of course, this is not a full-fledged directory lister like DIR (Windows) or ls (Unix) but many of those features can be implemented in this or similar tools, by using the stat module (which I've used in my PySiteCreator and other programs); the Python stat must be a wrapper over the C library with the same name, at least on Unix (AFAIK the native Windows SDK's directory and file system manipulation functions are different from POSIX ones, though the C standard library on Windows has many C stdio functions for compatibility and convenience).
Here is the code for the program, file_glob.py:
from __future__ import print_function ''' file_glob.py Lists filenames matching one or more wildcard patterns. Author: Vasudev Ram Copyright 2016 Vasudev Ram Web site: https://vasudevram.github.io Blog: http://jugad2.blogspot.com Product store: https://gumroad.com/vasudevram ''' import sys import glob sa = sys.argv lsa = len(sys.argv) if lsa < 2: print("{}: Must give one or more filename wildcard arguments.". format(sa[0])) sys.exit(1) for arg in sa[1:]: print("Files matching pattern {}:".format(arg)) for filename in glob.glob(arg): print(filename)I ran it multiple times with these files in my current directory. All of them are regular files except dir1 which is a directory.
$ dir /b dir1 f1.txt f2.txt f3.txt f4.txt f5.txt f6.txt f7.txt f8.txt f9.txt file_glob.py o1.txt out1 out3 test_fnmatch1.py test_fnmatch2.py test_glob.py~Here are a few different runs of the program with 0, 1 or 2 arguments, giving different outputs based on the patterns used.
$ python file_glob.py Must give one or more filename wildcard arguments.
$ python file_glob.py a Files matching pattern a
$ python file_glob.py *1 Files matching pattern *1: dir1 out1
$ python file_glob.py *txt Files matching pattern *txt: f1.txt f2.txt f3.txt f4.txt f5.txt f6.txt f7.txt f8.txt f9.txt o1.txt
$ python file_glob.py *txt *1 Files matching pattern *txt: f1.txt f2.txt f3.txt f4.txt f5.txt f6.txt f7.txt f8.txt f9.txt o1.txt Files matching pattern *1: dir1 out1
$ python file_glob.py *txt *py Files matching pattern *txt: f1.txt f2.txt f3.txt f4.txt f5.txt f6.txt f7.txt f8.txt f9.txt o1.txt Files matching pattern *py: file_glob.py test_fnmatch1.py test_fnmatch2.py
$ python file_glob.py f[2-5]*xt Files matching pattern f[2-5]*xt: f2.txt f3.txt f4.txt f5.txt
$ python file_glob.py f[!2-5]*xt Files matching pattern f[!2-5]*xt: f1.txt f6.txt f7.txt f8.txt f9.txt
$ python file_glob.py *mat* Files matching pattern *mat*: test_fnmatch1.py test_fnmatch2.py
$ python file_glob.py *e* *[5-8]* Files matching pattern *e*: file_glob.py test_fnmatch1.py test_fnmatch2.py test_glob.py~ Files matching pattern *[5-8]*: f5.txt f6.txt f7.txt f8.txt
$ python file_glob.py *[1-4]* Files matching pattern *[1-4]*: dir1 f1.txt f2.txt f3.txt f4.txt o1.txt out1 out3 test_fnmatch1.py test_fnmatch2.py
$ python file_glob.py a *txt b Files matching pattern a: Files matching pattern *txt: f1.txt f2.txt f3.txt f4.txt f5.txt f6.txt f7.txt f8.txt f9.txt o1.txt Files matching pattern b:As you can see from the runs, it works, including for ranges of wildcard characters, and the negation of them too (using the ! character inside the square brackets before the range). Enjoy. - Vasudev Ram - Online Python training and consulting Get updates on my software products / ebooks / courses. Jump to posts: Python DLang xtopdf Subscribe to my blog by email My ActiveState recipes Managed WordPress Hosting by FlyWheel
1 comment:
My apologies to people reading this via Planet Python, who may see the post twice - once now, and once after the next refresh of the planet's feed. This may happen because this time I put the "Python" label on the post after the first publish, and then went on to make a few last minute edits before re-publishing. So it got picked up too early. Those edits (mainly mention of PySiteCreator) will be seen in the next refresh. Usually I put that label last, after doing all the editing and re-editing ...
Post a Comment