I'm new to python and currently experimenting using argparse to add command line options. However my code is not working, despite looking at various online tutorials and reading up on argparse I still don't fully understand it. My problem is whenever I try to call my -option it gives me a find.py error: argument regex:
Here is my call:
./find.py ../Python -name '[0-9]*\.txt'
../Python is one directory behind my current one and has a list of files/directories. Without the -name option I print out the files with their path (this works fine) but with the -name option I want to print out files matching the regex but it won't work. Here is what I currently have:
#!/usr/bin/python2.7
import os, sys, argparse,re
from stat import *
def regex_type(s, pattern=re.compile(r"[a-f0-9A-F]")):
if not pattern.match(s):
raise argparse.ArgumentTypeError
return s
def main():
direc = sys.argv[1]
for f in os.listdir(direc):
pathname = os.path.join(direc, f)
mode = os.stat(pathname).st_mode
if S_ISREG(mode):
print pathname
parser = argparse.ArgumentParser()
parser.add_argument(
'-name', default=[sys.stdin], nargs="*")
parser.add_argument('regex', type=regex_type)
args = parser.parse_args()
if __name__ == '__main__':
main()
I tweaked your type function to be more informative:
Called with
I get:
So it tries to pass
sys.argv[1]
, the first string after the script name, to theregex_type
function. If it fails it issues the error message and usage.OK, the problem was the
..
; I'll make a directory:The strings following '-name' are allocated to that attribute. There's nothing in your code that will test them or pass them through the
regex_type
function. Only the first non-flag string does that.Reading
sys.argv[1]
initially does not remove it from the list. It's still there for use by the parser.I would set up a parser that uses a
store_true
--name
argument, and 2 positionals - one for thedir
and the other forregex
.After parsing check
args.name
. If false print the contents ofargs.dir
. If true, perform yourargs.regex
filter on those contents.glob
might be useful.The parser finds out what your user wants. Your own code acts on it. Especially as a beginner, it is easier and cleaner to separate the two steps.
With:
I get runs like:
and help:
If I change the
dir
line to:help is now
and runs are:
I get the error because it now requires a directory, even it is '.'.
Note that the script still uses:
My
main
loads thedir
, and applies theregex
filter to that list of names. Myargs.dir
replaces yourdirec
.