Should I also parse mandatory arguments with getopt(...) - python

"""
Saves a dir listing in a file
Usage: python listfiles.py -d dir -f filename [flags]
Arguments:
-d, --dir dir; ls of which will be saved in a file
-f, --file filename (if existing will be overwritten)
Flags:
-h, --help show this help
-v, --verbose be verbose
"""
...
def usage():
print __doc__
def main(args):
verbose = False
srcdir = filename = None
try:
opts, args = getopt.getopt(args,
'hvd:f:', ['help', 'verbose', 'dir=', 'file='])
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ('-h', '--help'):
usage()
sys.exit(0)
if opt in ('-v', '--verbose'):
verbose = True
elif opt in ('-d', '--dir'):
srcdir = arg
elif opt in ('-f', '--file'):
filename = arg
if srcdir and filename:
fsock = open(filename, 'w')
write_dirlist_tosock(srcdir, fsock, verbose)
fsock.close()
else:
usage()
sys.exit(1)
if __name__ == '__main__':
main(sys.argv[1:])
I am not sure if it is pythonic to use getopt() to also handle mandatory arguments. Would appreciate some suggestions

the getopt module is only for those users who are already familiar with the same module in C, the python standard argument handling is argparse.

"Mandatory Options" is a contradiction, and is not generally well supported by the various option parsing libraries; You should consider placing mandatory arguments as a positional arguments, not parsed by the option parser, this would agree with common practice much better.

Related

Python command line arguments - hope to print error when no argument

I have a following simple code:
import sys, getopt
ifile=''
ofile=''
try:
opts, args = getopt.getopt(sys.argv[1:],"h:i:o:")
except getopt.GetoptError as e:
print (str(e))
print("test.py -i input -o output")
sys.exit(2)
for o, a in opts:
if o == '-h':
print 'test.py -i input -o output'
sys.exit()
elif o == '-i':
ifile=a
elif o == '-o':
ofile=a
What should I need to add, if I want to print error (and also help) message 'test.py -i input -o output' when I execute just the script like:
$ python test.py
Thank you
You can write
if len(sys.argv) <= 1:
print('test.py -i input -o output')
exit(1)
after the imports, which basically means that if i don't have any arguments, print the message and quit running the script.
Just as an alternative, if you are interested, the documentation for getopts actually provides a suggestion to use argparse, which significantly reduces the lines of code you have to write to handle arguments.
Look at the bottom of the doc here:
https://docs.python.org/2/library/getopt.html#getopt.GetoptError
And here is the documentation for argparse
https://docs.python.org/2/library/argparse.html#module-argparse
The big bonus with argparse is that has a built in "help" that is nicely formatted. Look at the following example. You can take this code and test on your end too.
from argparse import ArgumentParser, RawTextHelpFormatter
parser = ArgumentParser(
description='This application will perform actions',
formatter_class=RawTextHelpFormatter
)
parser.add_argument(
'-i',
help='Things with i',
)
parser.add_argument(
'-o',
help='Things with o',
)
args = vars(parser.parse_args())
if args.get('i'):
print(args.get('i'))
elif args.get('o'):
print(args.get('o'))
else:
parser.error('Invalid options provided')
Just thought I'd share as an alternative.

Python command line arg with getopt does not work

I modified the sample code given here:
sample code for getopt
as follows, but it does not work. I am not sure what I am missing. I added a "-j" option to this existing code. Eventually, I want to add as many as required command option to meet my needs.
When I give input as below, it does not print anything.
./pyopts.py -i dfdf -j qwqwqw -o ddfdf
Input file is "
J file is "
Output file is "
Can you please let me know whats wrong here?
#!/usr/bin/python
import sys, getopt
def usage():
print 'test.py -i <inputfile> -j <jfile> -o <outputfile>'
def main(argv):
inputfile = ''
jfile = ''
outputfile = ''
try:
opts, args = getopt.getopt(argv,"hij:o:",["ifile=","jfile=","ofile="])
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
usage()
sys.exit()
elif opt in ("-i", "--ifile"):
inputfile = arg
elif opt in ("-j", "--jfile"):
jfile = arg
elif opt in ("-o", "--ofile"):
outputfile = arg
print 'Input file is "', inputfile
print 'J file is "', jfile
print 'Output file is "', outputfile
if __name__ == "__main__":
main(sys.argv[1:])
Your error is omitting a colon following the i option. As stated by the link you supplied:
options that require an argument should be followed by a colon (:).
Therefore, the corrected version of your program should contain the following:
try:
opts, args = getopt.getopt(argv,"hi:j:o:",["ifile=","jfile=","ofile="])
except getopt.GetoptError:
usage()
sys.exit(2)
Executing it with the specified arguments derives the expected output:
~/tmp/so$ ./pyopts.py -i dfdf -j qwqwqw -o ddfdf
Input file is " dfdf
J file is " qwqwqw
Output file is " ddfdf
However, as a comment to your question specifies, you should use argparse rather than getopt:
Note: The getopt module is a parser for command line options whose API is designed to be familiar to users of the C getopt() function. Users who are unfamiliar with the C getopt() function or who would like to write less code and get better help and error messages should consider using the argparse module instead.

how show error if no args was set in console trying execute python script

I need to write python script which need command arguments for executing. I have such code:
try:
opts, args = getopt.getopt(argv,"htt:tf:d:",["from=","to=","on="])
except getopt.GetoptError:
print 'logReader.py -f <from> -t <to> -d <on>'
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print 'logReader.py -f <from> -t <to> -d <on>'
sys.exit()
# elif opt
elif opt in ("-f", "--from"):
fromTime = arg
elif opt in ("-t", "--to"):
toTime = arg
elif opt in ("-d", "--on"):
onDate = arg
But than I run my script without any arguments it just do nothing. How can I add some check like if no args are specified the error message should be shown in the console (or help)
With no arguments set, opts will be an empty list:
if not opts:
print 'logReader.py -f <from> -t <to> -d <on>'
sys.exit(2)
You should really consider using the argparse module instead, which lets you specify that some command line options are mandatory.

Python usage not printing

im creating my first python "app" and im having problems with the args or lack of. If i execute the script with no arguments id expect a message stating usage, but instead im getting the following error
ERROR
unknown#ubuntu:~$ ./attack.py
Traceback (most recent call last):
File "./attack.py", line 60, in <module>
main(sys.argv[1:])
File "./attack.py", line 57, in main
print fread(FWORD)
File "./attack.py", line 19, in fread
flist = open(FWORD).readlines()
TypeError: coercing to Unicode: need string or buffer, NoneType found
CODE
#!/usr/bin/python
import sys, getopt, socket, fileinput, traceback
from Queue import Queue
from threading import Thread
def usage():
print "-h --help: help\n"
print "-f --file: File to read potential Sub-domains from.\n"
print "-p --PROXY: PROXY address and port. e.g http://192.168.1.64:8080\n"
print "-d --DOMAIN: DOMAIN to bruteforce.\n"
print "-t --thread: Thread count.\n"
print "-e: Turn debug on.\n"
sys.exit()
def fread(FWORD, *args):
flist = open(FWORD).readlines()
return flist
#def addcheck(fcontent):
def main(argv):
PROXY = None
DOMAIN = None
FWORD= None
try:
opts, argv =getopt.getopt(argv, "h:f:p:d:t:e",["help", "file=", "PROXY=", "DOMAIN=", "thread="])
except getopt.GetoptError as err:
print str(err)
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit()
elif opt in ("-f", "--file"):
FWORD = arg
elif opt in ("-p", "--PROXY"):
PROXY = arg
elif opt in ("-d", "--DOMAIN"):
DOMAIN = arg
elif opt in ("-t", "--thread"):
thread = arg
elif opt in '-e':
global _debug
_debug = 1
else:
usage()
sys.exit()
print fread(FWORD)
if __name__ == "__main__":
main(sys.argv[1:])
Ok thanks all for the comments and pointers. ZMO im going to go with docopt it looks clean and simple (simple just like me). Im not entire sure what i need to do to my old code so am uploading what i think i need to do. Can anyone tell me if this is the right direction?
What do i do with def main() now? and
#!/usr/bin/python
import sys, getopt, socket, fileinput, traceback
from Queue import Queue
from threading import Thread
def fread(FWORD, *args):
flist = open(FWORD).readlines()
return flist
def main(argv):
"""
Usage:
your_script.py [-f <file>] [-p <proxy>] [-d <domain>] [-t] [-v]
your_script.py -h | --help
Options:
-h --help Show this screen.
-f --file File to read potential Sub-domains from.
-p --proxy Proxy address and port. [default: http://127.0.0.1:8080]
-d --domain Domain to bruteforce.
-t --thread Thread count.
-v --verbose Turn debug on.
"""
# […] your code (NOT SURE WHAT CODE YOU MEAN?
if __name__ == "__main__":
from docopt import docopt
arguments = docopt(__doc__, version='0.1a')
print fread(FWORD)
geptopt is deprecated in modern python, you should use argparse instead. I personally prefer the 3rd party docopt
It's useless to give the sys.argv array as argument to main() because you import the sys module globally in your module context (and there are many other things you'd use from sys aside from argv). Your code would only make sense if you were doing the import in the if __name__ == "__main__", but then that would be not good python practice. A better thing to do is to actually parse the arguments and then give the returned NamedTuple as an argument to main().
Argparse example
# […] your code
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='Your script.')
parser.add_argument('--file', '-f', metavar='FILE', dest='file', type=file,
help='File to read potential Sub-domains from.')
parser.add_argument('--proxy', '-p', dest='proxy', action='store',
help='Proxy address and port.', default='http://127.0.0.1:8080')
parser.add_argument('--domain', '-d', dest='domain', action='store',
help='Domain to bruteforce.')
parser.add_argument('--thread', '-t', dest='thread', action='store_true',
help='Thread count.')
parser.add_argument('--verbose', '-v', dest='verbose', action='store_true',
help='Turn debug on.')
args = parser.parse_args()
main(args)
docopt example
Your script presentation.
"""
Usage:
your_script.py [-f <file>] [-p <proxy>] [-d <domain>] [-t] [-v]
your_script.py -h | --help
Options:
-h --help Show this screen.
-f --file File to read potential Sub-domains from.
-p --proxy Proxy address and port. [default: http://127.0.0.1:8080]
-d --domain Domain to bruteforce.
-t --thread Thread count.
-v --verbose Turn debug on.
"""
# […] your code
if __name__ == "__main__":
from docopt import docopt
arguments = docopt(__doc__, version='Naval Fate 2.0')
main(arguments) # here using the parameter makes sense ;-)

Python optparse not seeing argument

I am trying to pass '-f nameoffile' to the program when I call it from the command line. I got this from the python sites documentation but when I pass '-f filename' or '--file=filename' it throws the error that I didnt pass enough arguments. If i pass -h the programs responds how it should and gives me the help. Any ideas? I imagine its something simple that I am overlooking. Any and all help is great, thanks, Justin.
[justin87#el-beasto-loco python]$ python openall.py -f chords.tar
Usage: openall.py [options] arg
openall.py: error: incorrect number of arguments
[justin87#el-beasto-loco python]$
#!/usr/bin/python
import tarfile
import os
import zipfile
from optparse import OptionParser
def check_tar(file):
if tarfile.is_tarfile(file):
return True
def open_tar(file):
try:
tar = tarfile.open(file)
tar.extractall()
tar.close()
except tarfile.ReadError:
print "File is somehow invalid or can not be handled by tarfile"
except tarfile.CompressionError:
print "Compression method is not supported or data cannot be decoded"
except tarfile.StreamError:
print "Is raised for the limitations that are typical for stream-like TarFile objects."
except tarfile.ExtractError:
print "Is raised for non-fatal errors when using TarFile.extract(), but only if TarFile.errorlevel== 2."
def check_zip(file):
if zipfile.is_zipfile(file):
return True
def open_zip(file):
try:
zip = zipfile.ZipFile(file)
zip.extractall()
zip.close()
#open the zip
print "GOT TO OPENING"
except zipfile.BadZipfile:
print "The error raised for bad ZIP files (old name: zipfile.error)."
except zipfile.LargeZipFile:
print "The error raised when a ZIP file would require ZIP64 functionality but that has not been enabled."
rules = ((check_tar, open_tar),
(check_zip, open_zip)
)
def checkall(file):
for checks, extracts in rules:
if checks(file):
return extracts(file)
def main():
usage = "usage: %prog [options] arg"
parser = OptionParser(usage)
parser.add_option("-f", "--file", dest="filename",
help="read data from FILENAME")
(options, args) = parser.parse_args()
if len(args) != 1:
parser.error("incorrect number of arguments")
file = options.filename
checkall(file)
if __name__ == '__main__':
main()
Your problem is probably the if len(args) != 1:. That is looking for an additional argument (i.e. not an option). If you remove that check and look at your options dictionary you should see {'filename': 'blah'}.
Your input filename isn't an option to the program, it's an argument:
def main():
usage = "Usage: %prog [options] FILE"
description = "Read data from FILE."
parser = OptionParser(usage, description=description)
(options, args) = parser.parse_args()
if len(args) != 1:
parser.error("incorrect number of arguments")
file = args[0]
checkall(file)
You can usually tell the difference because options generally have sensible defaults while arguments don't.
After parsing the options out of the argument list, you check that you were passed an argument. This is independent of the argument to -f. It sounds like you're just not passing this argument. Since you also don't actually use this argument, you should probably just remove the check on len(args).
You should set the 'action' attribute in the 'add_option()' method to 'store', this tells the optparse object to store the argument immediately following the option flag, though this is the default behavior. The value following the flag will then be stored in 'options.filename' and not in args. I also think that the
if len(args) != 1:
is also an issue, you will get the same message if len(args) is greater than or less than 1.

Categories