Setting optional system arguments via command prompt - python

I am doing a project in which I want to specify one system argument on my cmd right after the script.py. My problem is that I want to specify another argument in which is optional, and the user may or may not want to give that argument. Therefore, I am struggling how to deal with the fact that the system argument might or might not be given by the user and how to read that. If everything sounds confusing, the following text might clarify:
The user types the following on the command prompt to run the program:
python script.py file.txt
I want to add an argument which may or may not be given, like:
python script.py file.txt file_added.txt
As I read these arguments on my main script, I though that this problem would solve:
If sys.argv[2] is not None:
file2 = f"\{sys.argv[2]}"
However, I still getting IndexError when doing that. So, is there a simple way to bypass such problem?

If sys.argv holds less than 2 items, you'll get an IndexError. So wrap the statement around with a try block
try:
filename = sys.argv[2]
except IndexError:
filename = None
if filename:
# ... do something

A way to accomplish this would be to check the length of sys.argv. If the length is 3 you'll know that a second argument was passed (3 because the first argument is script.py). So something along the lines:
if len(sys.argv) == 3:
file2 = f"\{sys.argv[2]}"

Here, sys.argv[2] is not None you are checking if 3rd element is None or not and that is the issue.
You are indexing outside the length of argv array and index error.
If you only have max 2 input then you could check the length of argv like if len(sys.argv) == 3 and that means you have got both the input and then you can access them via sys.argv[1] and sys.argv[2]

You can use argsparse which is a built in library in python, which makes it easy to handle command line arguments. Go to the link https://docs.python.org/3/library/argparse.html to know mor, but the basic implementation for your usecase will be like this.
import argparse
parser = argparse.ArgumentParser(description='Enter filenames')
parser.add_argument('-file', type=str,help='enter the file name',dest='filename1')
parser.add_argument('--optional','--op',type=str, dest='filename2',help='enter optional filename')
args = parser.parse_args()
file1=args.filename1
file2=args.filename2
Then in the cmd you can invoke it as
python script.py -filename="file1.txt"
or
python script.py -filename="file1.txt" --optional="file2.txt"
or
python script.py -filename="file1.txt" --op="file2.txt"

You are looking for argv[1], argv[2], and so on.
This should work:
for filename in sys.argv[1:]:
readfile(filename)

Related

Python: Subprocess works different to terminal. What I have to change?

I have to Python scripts: Tester1.py and Tester2.py.
Within Tester1 I want to start from time to time Tester2.py. I also want to pass Tester2.py some arguments. At the moment my code looks like this:
Tester1:
subprocess.call(['python3 Tester2.py testString'])
Tester2:
def start():
message = sys.argv[1]
print(message)
start()
Now my problem: If I run with my terminal Tester2 like 'python3 Tester2.py testString'my console prints out testString. But if I run Tester1 and Tester1 tries to start Tester2, I get an IndexError: "list index out of range".
How do I need to change my code to get everything working?
EDIT:
niemmi told me that I have to change my code to:
subprocess.call(['python3', 'Tester2.py', 'testString'])
but now I get a No such file or directory Error although both scripts are in the same directory. Someone knows why?
You need to provide the arguments either as separate elements on a list or as a string:
subprocess.call(['python3', 'Tester2.py', 'testString'])
# or
subprocess.call('python3 Tester2.py testString')
Python documentation has following description:
args is required for all calls and should be a string, or a sequence of program arguments. Providing a sequence of arguments is generally preferred, as it allows the module to take care of any required escaping and quoting of arguments (e.g. to permit spaces in file names). If passing a single string, either shell must be True (see below) or else the string must simply name the program to be executed without specifying any arguments.

Command Line Arguments in Python with sys.argv

I want to use sys.argv to access the arguments passed to the script. Here is my code :
if __name__ == '__main__':
data = {}
if len(sys.argv) >= 2 :read_inputs(data, sys.argv[1])
else : print "ERROR : the config file is required in the command line"
if len(sys.argv) >= 3 :data['Parameters']['Mode'] = sys.argv[2]
print_data(data)
I understand that sys.argv[1] and sys.argv[2] refer to the arguments.
My arguments are contained in a text file.
What I cannot understand is how can I tell the code that it needs to read the arguments in that exact text file.
I used python Interface.py config.txt but it didn't work.
Any ideas ?
If I understand you correctly you want what would normally be on the command line to be in that file, right?
You can do that using command substitution python Interface.py $(< config.txt), as seen here
Although not a direct answer to your question, I would highly recommend using the Python argparse module to parse command line argument. I your case I would add a "-c, --config" option that specifies the location of the config file that you want to use. See the documentation for examples: https://docs.python.org/3/library/argparse.html

Python command line parameters

I am just starting with python so I am struggling with a quite simple example. Basically I want pass the name of an executable plus its input via the command line arguments, e.g.:
python myprogram refprogram.exe refinput.txt
That means when executing myprogram, it executes refprogram.exe and passes to it as argument refinput. I tried to do it the following way:
import sys, string, os
print sys.argv
res = os.system(sys.argv(1)) sys.argv(2)
print res
The error message that I get is:
res = os.system(sys.argv(1)) sys.argv(2)
^
SyntaxError: invalid syntax
Anyone an idea what I am doing wrong?
I am running Python 2.7
This line
res = os.system(sys.argv(1)) sys.argv(2)
Is wrong in a couple of ways.
First, sys.argv is a list, so you use square brackets to access its contents:
sys.argv[1]
sys.argv[2]
Second, you close out your parentheses on os.system too soon, and sys.argv(2) is left hanging off of the end of it. You want to move the closing parenthesis out to the very end of the line, after all of the arguments.
Third, you need to separate the arguments with commas, a simple space won't do.
Your final line should look like this:
res = os.system(sys.argv[1], sys.argv[2])
A far, far better way to do this is with the argparse library. The envoy wrapper library makes subprocess easier to work with as well.
A simple example:
import argparse
import envoy
def main(**kwargs):
for key, value in kwargs.iteritems():
print key, value
cmd = '{0} {1}'.format(kwargs['program'], ' '.join(kwargs['infiles']))
r = envoy.run(cmd)
print r.std_out
print r.std_err
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Get a program and run it with input', version='%(prog)s 1.0')
parser.add_argument('program', type=str, help='Program name')
parser.add_argument('infiles', nargs='+', type=str, help='Input text files')
parser.add_argument('--out', type=str, default='temp.txt', help='name of output file')
args = parser.parse_args()
main(**vars(args))
This reads in the arguments, parses them, then sends them to the main method as a dictionary of keywords and values. That lets you test your main method independently from your argument code, by passing in a preconstructed dictionary.
The main method prints out the keywords and values. Then it creates a command string, and passes that to envoy to run. Finally, it prints the output from the command.
If you have pip installed, envoy can be installed with pip install envoy. The easiest way to get pip is with the pip-installer.
sys.argv is a list, and is indexed using square brackets, e.g. sys.argv[1]. You may want to check len(sys.argv) before indexing it as well.
Also, if you wanted to pass parameters to os.system(), you might want something like os.system(' '.join(sys.argv[1:])), but this won't work for arguments with spaces. You're better off using the subprocess module.
sys.argv is a list
import sys, string, os
print sys.argv
res = os.system(sys.argv[1]) sys.argv[2]
print res
If you are running Python 2.7 it is recommended to use the new subprocess module.
In this case you would write
import sys, subprocess
result = subprocess.check_output(sys.argv[1], sys.argv[2])

python sys.argv differentiate int and string

Simply put, how can I differentiate these two in test.py:
python test.py 1
python test.py '1'
Workaround is OK.
Edit:
This workaround looks cool but too complex: argparse
Let the invoker specify args later, in python code use arg = input('Please enter either an integer or a string')
And other workarounds as presented in the answers of this question.
Thank you all for the replies. Every body +1.
The quotes are consumed by the shell. If you want to get them into python, you'll have to invoke like python test.py 1 "'2'" "'3'" 4
It is common handling of args, performed by shell. " and ' are ignored, since you may use them to pass, for instance, few words as one argument.
This means that you can't differentiate '1' and 1 in Python.
The shell command line doesn't support passing arguments of different types. If you want to have commands with arguments of different types you need to write your own command line or at least your own command parser.
Variant 1:
Usage:python test.py "1 2 '3' '4'"
Implementation:
command = sys.argv[1]
arguments = map(ast.literal_eval, command.split())
print arguments
Variant 2:
Usage:
python test.py
1 2 '3' 4'
5 6 '7' 8'
Implementation:
for line in sys.stdin:
arguments = map(ast.literal_eval, line.split())
print arguments
(Of course, you'd probably want to use raw_input to read the command lines, and readline when it is available, that's merely an example.)
A much better solution would be to actually know what kind of arguments you're expected to get and parse them as such, preferably by using a module like argparse.
Windows-specific:
# test.py
import win32api
print(win32api.GetCommandLine())
Example:
D:\>python3 test.py 3 "4"
C:\Python32\python3.EXE test.py 3 "4"
You can then parse the command line yourself.
As you can see from your experiment, the quotes are gone by the time Python is invoked. You'll have to change how the Python is invoked.
I'm not sure how correct I am, but if you're using only integer command line arguments, you can typecast it to be int.
suppose (in *nix), I run my program as:
./test.py 1
I can in my program say something line
import sys
def main():
a=int(sys.argv[1])

What does "sys.argv[1]" mean? (What is sys.argv, and where does it come from?)

I'm currently teaching myself Python and was just wondering (In reference to my example below) in simplified terms what the sys.argv[1] represents. Is it simply asking for an input?
#!/usr/bin/python3.1
# import modules used here -- sys is a very standard one
import sys
# Gather our code in a main() function
def main():
print ('Hello there', sys.argv[1])
# Command line args are in sys.argv[1], sys.argv[2] ..
# sys.argv[0] is the script name itself and can be ignored
# Standard boilerplate to call the main() function to begin
# the program.
if __name__ == '__main__':
main()
You may have been directed here because you were asking about an IndexError in your code that uses sys.argv. The problem is not in your code; the problem is that you need to run the program in a way that makes sys.argv contain the right values. Please read the answers to understand how sys.argv works.
If you have read and understood the answers, and are still having problems on Windows, check if Python Script does not take sys.argv in Windows fixes the issue. If you are trying to run the program from inside an IDE, you may need IDE-specific help - please search, but first check if you can run the program successfully from the command line.
I would like to note that previous answers made many assumptions about the user's knowledge. This answer attempts to answer the question at a more tutorial level.
For every invocation of Python, sys.argv is automatically a list of strings representing the arguments (as separated by spaces) on the command-line. The name comes from the C programming convention in which argv and argc represent the command line arguments.
You'll want to learn more about lists and strings as you're familiarizing yourself with Python, but in the meantime, here are a few things to know.
You can simply create a script that prints the arguments as they're represented. It also prints the number of arguments, using the len function on the list.
from __future__ import print_function
import sys
print(sys.argv, len(sys.argv))
The script requires Python 2.6 or later. If you call this script print_args.py, you can invoke it with different arguments to see what happens.
> python print_args.py
['print_args.py'] 1
> python print_args.py foo and bar
['print_args.py', 'foo', 'and', 'bar'] 4
> python print_args.py "foo and bar"
['print_args.py', 'foo and bar'] 2
> python print_args.py "foo and bar" and baz
['print_args.py', 'foo and bar', 'and', 'baz'] 4
As you can see, the command-line arguments include the script name but not the interpreter name. In this sense, Python treats the script as the executable. If you need to know the name of the executable (python in this case), you can use sys.executable.
You can see from the examples that it is possible to receive arguments that do contain spaces if the user invoked the script with arguments encapsulated in quotes, so what you get is the list of arguments as supplied by the user.
Now in your Python code, you can use this list of strings as input to your program. Since lists are indexed by zero-based integers, you can get the individual items using the list[0] syntax. For example, to get the script name:
script_name = sys.argv[0] # this will always work.
Although interesting, you rarely need to know your script name. To get the first argument after the script for a filename, you could do the following:
filename = sys.argv[1]
This is a very common usage, but note that it will fail with an IndexError if no argument was supplied.
Also, Python lets you reference a slice of a list, so to get another list of just the user-supplied arguments (but without the script name), you can do
user_args = sys.argv[1:] # get everything after the script name
Additionally, Python allows you to assign a sequence of items (including lists) to variable names. So if you expect the user to always supply two arguments, you can assign those arguments (as strings) to two variables:
user_args = sys.argv[1:]
fun, games = user_args # len(user_args) had better be 2
So, to answer your specific question, sys.argv[1] represents the first command-line argument (as a string) supplied to the script in question. It will not prompt for input, but it will fail with an IndexError if no arguments are supplied on the command-line following the script name.
sys.argv[1] contains the first command line argument passed to your script.
For example, if your script is named hello.py and you issue:
$ python3.1 hello.py foo
or:
$ chmod +x hello.py # make script executable
$ ./hello.py foo
Your script will print:
Hello there foo
sys.argv is a list.
This list is created by your command line, it's a list of your command line arguments.
For example:
in your command line you input something like this,
python3.2 file.py something
sys.argv will become a list ['file.py', 'something']
In this case sys.argv[1] = 'something'
Just adding to Frederic's answer, for example if you call your script as follows:
./myscript.py foo bar
sys.argv[0] would be "./myscript.py"
sys.argv[1] would be "foo" and
sys.argv[2] would be "bar" ... and so forth.
In your example code, if you call the script as follows ./myscript.py foo , the script's output will be "Hello there foo".
Adding a few more points to Jason's Answer :
For taking all user provided arguments: user_args = sys.argv[1:]
Consider the sys.argv as a list of strings as (mentioned by Jason). So all the list manipulations will apply here. This is called "List Slicing". For more info visit here.
The syntax is like this: list[start:end:step]. If you omit start, it will default to 0, and if you omit end, it will default to length of list.
Suppose you only want to take all the arguments after 3rd argument, then:
user_args = sys.argv[3:]
Suppose you only want the first two arguments, then:
user_args = sys.argv[0:2] or user_args = sys.argv[:2]
Suppose you want arguments 2 to 4:
user_args = sys.argv[2:4]
Suppose you want the last argument (last argument is always -1, so what is happening here is we start the count from back. So start is last, no end, no step):
user_args = sys.argv[-1]
Suppose you want the second last argument:
user_args = sys.argv[-2]
Suppose you want the last two arguments:
user_args = sys.argv[-2:]
Suppose you want the last two arguments. Here, start is -2, that is second last item and then to the end (denoted by :):
user_args = sys.argv[-2:]
Suppose you want the everything except last two arguments. Here, start is 0 (by default), and end is second last item:
user_args = sys.argv[:-2]
Suppose you want the arguments in reverse order:
user_args = sys.argv[::-1]
sys.argv is a list containing the script path and command line arguments; i.e. sys.argv[0] is the path of the script you're running and all following members are arguments.
To pass arguments to your python script
while running a script via command line
> python create_thumbnail.py test1.jpg test2.jpg
here,
script name - create_thumbnail.py,
argument 1 - test1.jpg,
argument 2 - test2.jpg
With in the create_thumbnail.py script i use
sys.argv[1:]
which give me the list of arguments i passed in command line as
['test1.jpg', 'test2.jpg']
sys.argv is a attribute of the sys module. It says the arguments passed into the file in the command line. sys.argv[0] catches the directory where the file is located. sys.argv[1] returns the first argument passed in the command line. Think like we have a example.py file.
example.py
import sys # Importing the main sys module to catch the arguments
print(sys.argv[1]) # Printing the first argument
Now here in the command prompt when we do this:
python example.py
It will throw a index error at line 2. Cause there is no argument passed yet. You can see the length of the arguments passed by user using if len(sys.argv) >= 1: # Code.
If we run the example.py with passing a argument
python example.py args
It prints:
args
Because it was the first arguement! Let's say we have made it a executable file using PyInstaller. We would do this:
example argumentpassed
It prints:
argumentpassed
It's really helpful when you are making a command in the terminal. First check the length of the arguments. If no arguments passed, do the help text.
sys.argv will display the command line args passed when running a script or you can say sys.argv will store the command line arguments passed in python while running from terminal.
Just try this:
import sys
print sys.argv
argv stores all the arguments passed in a python list. The above will print all arguments passed will running the script.
Now try this running your filename.py like this:
python filename.py example example1
this will print 3 arguments in a list.
sys.argv[0] #is the first argument passed, which is basically the filename.
Similarly, argv[1] is the first argument passed, in this case 'example'.

Categories

Resources