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

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.

Related

Python Programm, how to use console input on file execution?

Let´s say I execute a python file like a program in Ubuntu
python filename.py --input1 --input2
How can I use those 2 inputs in my code? (If even possible with python)
BTW I would like to do this on Windows, not Linux.
For example, my code contains a function that takes 1 argument, in form of a string.
I could just do that argument input as input() while the code is running, but I would like to specify it when I execute the code already.
I recommend you take a look at argparse. https://docs.python.org/3.7/howto/argparse.html
Or
$ python
>>> import argparse
>>> help(argparse)
This is certainly possible and in fact even bread and butter in python and other script languages.
In python there is even the getopt module that helps you with that if you are familiar with the c implementation.
Copy-paste from official python documentation:
import getopt, sys
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
except getopt.GetoptError as err:
# print help information and exit:
print str(err) # will print something like "option -a not recognized"
usage()
sys.exit(2)
output = None
verbose = False
for o, a in opts:
if o == "-v":
verbose = True
elif o in ("-h", "--help"):
usage()
sys.exit()
elif o in ("-o", "--output"):
output = a
else:
assert False, "unhandled option"
# ...
if __name__ == "__main__":
main()
Official documentation is here: https://docs.python.org/2/library/getopt.html
For tutorials, see for example: https://www.tutorialspoint.com/python/python_command_line_arguments.htm
On the other hand argparse is easier if you like to get it done in an easier but not c-like way. For that, see the other answer.
For a simple case, you can just use sys.argv as follows:
# in your source.py
from sys import argv
arg1 = argv[1] # If your input is a "numerci type" , apply the the appropriate
arg2 = argv[2] # conversion by using (int, float)
...
Then you can execute your code, by:
python source.py arg1 arg2

Python script to take multiple number of arguments from shell

I am trying to take multiple files as input from terminal. the input number may vary from atleast 1 to many. Here is the input for my program
F3.py -e <Energy cutoff> -i <inputfiles>
I want the parameter -i to take any number of values from 1 to multiple.e.g.
F3.py -e <Energy cutoff> -i file1 file2
F3.py -e <Energy cutoff> -i *.pdb
Right now it takes only the first file and then stops.
This is what I have so far:
def main(argv):
try:
opts,args=getopt.getopt(argv,"he:i:")
for opt,arg in opts:
if opt=="-h":
print 'F3.py -e <Energy cutoff> -i <inputfiles>'
sys.exit()
elif opt == "-e":
E_Cut=float(arg)
print 'minimum energy=',E_Cut
elif opt == "-i":
files.append(arg)
print files
funtction(files)
except getopt.GetoptError:
print 'F3.py -e <Energy cutoff> -i <inputfiles>'
sys.exit(2)
Any help would be appreciated. Thanks
Try using the #larsks suggestion, the next snippet should work for your use case:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input', help='Input values', nargs='+', required=True)
args = parser.parse_args()
print args
kwargs explanation:
nargs allows you to parse the values as a list, so you can iterate over using something like: for i in args.input.
required makes this argument mandatory, so you must add at least one element
By using the argparse module you also got the -h option to describe your params. So try using:
$ python P3.py -h
usage: a.py [-h] -i INPUT [INPUT ...]
optional arguments:
-h, --help show this help message and exit
-i INPUT [INPUT ...], --input INPUT [INPUT ...]
Input values
$ python P3.py -i file1 file2 filen
Namespace(input=['file1', 'file2', 'filen'])
If you insist on using getopt you will have to combine multiple argument with delimeter other than space like , and then modify your code accordingly like this
import getopt
import sys
try:
opts,args=getopt.getopt(sys.argv[1:],"he:i:")
for opt,arg in opts:
if opt=="-h":
print 'F3.py -e <Energy cutoff> -i <inputfiles>'
sys.exit()
elif opt == "-e":
E_Cut=float(arg)
print 'minimum energy=',E_Cut
elif opt == "-i":
files = arg.split(",")
print files
#funtction(files)
except getopt.GetoptError:
print 'F3.py -e <Energy cutoff> -i <inputfiles>'
sys.exit(2)
When you run this you will get output
>main.py -e 20 -i file1,file2
minimum energy= 20.0
['file1', 'file2']
NOTE
I have commented your function call and removed unwrap your code from main function, you can redo these things in your code it will not change your result.

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.

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 ;-)

Pass bash argument to python script

I am trying to create a bash script which passes its own argument onto a python script. I want it to work like this.
If I run it as this:
script.sh latest
Then within the bash script it runs a python script with the "latest" argument like this:
python script.py latest
Likewise if the bash script is run with the argument 123 then the python script as such:
python script.py 123
Can anyone help me understand how to accomplish this please?
In this case the trick is to pass however many arguments you have, including the case where there are none, and to preserve any grouping that existed on the original command line.
So, you want these three cases to work:
script.sh # no args
script.sh how now # some number
script.sh "how now" "brown cow" # args that need to stay quoted
There isn't really a natural way to do this because the shell is a macro language, so they've added some magic syntax that will just DTRT.
#!/bin/sh
python script.py "$#"
In the pythonscript script.py use getopt.getopt(args, options[, long_options]) to get the arguments.
Example:
import getopt, sys
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
except getopt.GetoptError as err:
# print help information and exit:
print str(err) # will print something like "option -a not recognized"
usage()
sys.exit(2)
output = None
verbose = False
for o, a in opts:
if o == "-v":
verbose = True
elif o in ("-h", "--help"):
usage()
sys.exit()
elif o in ("-o", "--output"):
output = a
else:
assert False, "unhandled option"
# ...
if __name__ == "__main__":
main()
A very goo buit-in parser is argparse. Yo can use it as follows:
import argparse
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
const=sum, default=max,
help='sum the integers (default: find the max)')
args = parser.parse_args()
print(args.accumulate(args.integers))
In bash, arguments passed to the script are accessed with the $# notation (# being a number. Using $# exactly like that should give you the number of args passed). So if you wanted to pass arguments:
Calling the script:
`#script.sh argument`
Within the script:
python script.py "$1"

Categories