This question already has answers here:
What does "sys.argv[1]" mean? (What is sys.argv, and where does it come from?)
(9 answers)
Closed 6 years ago.
What does the following chunk of code mean? I don't understand the concept of sys.argv. I heard it has something to do with command-line prompts but my vocabulary isn't good enough to understand that. Also the output is strange. I don't understand how a list is pulled up nor how the elements get in there or even where they come from and what they mean. This is really confusing me, so help understanding it would be much appreciated. Please use beinner terms so I can understand it.
import sys
print 'Number of arguments:', len(sys.argv), 'arguments.'
print 'Argument List:', str(sys.argv)
Most programs accept arguments to change how they behave. e.g.
grep some_string myfile.ext
This command (on unix systems) looks for 'some_string' in myfile.ext and prints matching lines to the console.
So the question is how does grep (the program that is being run), know what to look for, or what file to look in? The answer is obvious -- It gets passed those arguments via the command line. You have the power to pass arguments from the commandlint to your python programs too:
python my_python_file.py argument1 argument2
In this case, if my_python_file.py had the contents in your question, sys.argv would contain ['my_python_file.py', 'argument1', 'argument2']
And so you can look in sys.argv and see 'argument1' in there and have your code take certain actions accordingly. Note that it is fairly uncommon to parse sys.argv by hand unless it is a really simple case. Normally, you would use something like argparse to parse the arguments for you and give you back the parsed information in a much more easy to manage format.
sys.argv is a list of strings containing the arguments when the Python script was executed (i.e. >> python main.py arg1 arg2).
Note that the first argument will always be the name of the command. The first "actual" argument is located in sys.argv[1] (assuming at least one argument was passed in).
Related
I'm trying to create a basic function that will pass a filename and arguments to a program using call() from the subprocess module. The filename and arguments are variables. When I use call() it takes the variables but the called program reads their strings with " included.
Here's the code in question:
from subprocess import call
def mednafen():
print "Loading "+romname+"..."
call(["mednafen", args, romname])
print "Mednafen closed."
romname="kirby.zip"
args="-fs 1"
mednafen()
I expected this would execute
mednafen -fs 1 kirby.zip
but instead it appears to interpret the variable's strings as this:
mednafen "-fs 1" "kirby.zip"
Because of this, mednafen isn't able to run because it can't parse an argument that starts with ".
It works as expected if I use shell=True but that feature is apparently strongly discouraged because it's easy to exploit?
call("mednafen "+ args +" "+romname+"; exit", shell=True)
Is there a way to do this without using the shell=True format?
Well, yes. That's exactly what the documentation says it does. Create and pass a list containing the command and all arguments instead.
EDIT: The solution suggested by Jonas Wielicki is to make sure every single string that would normally be separated by spaces in shell syntax is listed as a separate item; That way call() will read them properly. shlex is unnecessary.
args = ["-fs", "1"]
call(['mednafen']+args+[rom])
My initial (less concise) solution:
shlex.split() takes the variables/strings I feed it and converts them into a list of string literals, which in turn causes the called command to parse them correctly rather than interpreting the variables as strings within quotes.
So instead of the argument being treated like "-fs 0" I'm getting -fs 0 like I originally wanted.
import shlex
call(shlex.split("mednafen "+args+" "+romname))
I am trying to use Python to run an executable (Windows 7) with parameters. I have been able to make the program run, but the amount of parameters I can use that will prove the Python script worked with parameters is limited. The best one is formatted like so:
-debugoutput debug.txt
I have tested this using a windows shortcut with an edited target and it works, it creates a debug output in the program directory.
Here is the code I am using:
import subprocess
args = [r"C:\Users\MyName\LevelEditor\LevelEditor.exe", "-debugoutput debug.txt"]
subprocess.call(args)
This does run the program, but the debug output is not created. I have tried putting an "r" in front of the parameter but this made no difference. I assume it is a simple formatting error but I can't find any examples to learn from that are doing the same thing.
UPDATE:
Thanks for the answers everyone, all the same, simple formatting error indeed.
In-code definition results in invocation of shell command line:
C:\Users\MyName\LevelEditor\LevelEditor.exe "-debugoutput debug.txt"
As you can see, by merging -debugoutput debug.txt to single list element, you explicitly stated that space between them shouldn't be parsed as command line argument separator.
To achieve expected behavior put file name string as separate element to argument list.
[r"C:\Users\MyName\LevelEditor\LevelEditor.exe", "-debugoutput", "debug.txt"]
As far as I know you need to split the arguments by the space, so your args would look like:
args = [r"C:\Users\MyName\LevelEditor\LevelEditor.exe", "-debugoutput", "debug.txt"]
Does that work?
I do not know if it works, but
import subprocess
args = [r"C:\Users\MyName\LevelEditor\LevelEditor.exe", "-debugoutput", "debug.txt"]
subprocess.run(args)
Following the docs
I'm trying to take the output of one script and pass it using sys.argv to my python script.
The question I have is whether there's a way to accomplish this similar to
python runfile.py $(node parse.js)
For testing, runfile.py just consists of:
import sys
print sys.argv
But, as you might've guessed, that just logs ['runfile.py'].
Am I totally barking up the wrong tree here? If so, can someone explain or link to an explanation of how to pass the output of, say, a javascript file to a python script?
Edit: is there a way to mark the $(node parse.js) part as a separate argument that should be evaluated?
Instead of passing the output of node parse.js to your python script via command line arguments (sys.argv) you could use stdin and unix pipes:
node parse.js | python runfile.py
And edit runfile.py to look like:
import sys
print sys.stdin
Is anyone able to tell me how to write a conditional for an argument on a python script? I want it to print "Argument2 Entered" if it is run with a second command line arguments such as:
python script.py argument1 argument2
And print "No second argument" if it is run without command line arguments, like this:
python script.py argument1
Is this possible?
import sys
if len(sys.argv)==2: # first entry in sys.argv is script itself...
print "No second argument"
elif len(sys.argv)==3:
print "Second argument"
There are many answers to this, depending on what exactly you want to do and how much flexibility you are likely to need.
The simplest solution is to examine the variable sys.argv, which is a list containing all of the command-line arguments. (It also contains the name of the script as the first element.) To do this, simply look at len(sys.argv) and change behaviour based on its value.
However, this is often not flexible enough for what people expect command-line programs to do. For example, if you want a flag (-i, --no-defaults, ...) then it's not obvious how to write one with just sys.argv. Likewise for arguments (--dest-dir="downloads"). There are therefore many modules people have written to simplify this sort of argument parsing.
The built-in solution is argparse, which is powerful and pretty easy-to-use but not particularly concise.
A clever solution is plac, which inspects the signature of the main function to try to deduce what the command-line arguments should be.
There are many ways to do this simple thing in Python. If you are interested to know more than I recommend to read this article. BTW I am giving you one solution below:
import click
'''
Prerequisite: # python -m pip install click
run: python main.py ttt yyy
'''
#click.command(context_settings=dict(ignore_unknown_options=True))
#click.argument("argument1")
#click.argument("argument2")
def main(argument1, argument2):
print(f"argument1={argument1} and argument2={argument2}")
if __name__ == '__main__':
main()
Following block should be self explanatory
$ ./first.py second third 4th 5th
5
$ cat first.py
#!/usr/bin/env python
import sys
print (len(sys.argv))
This is related to many other posts depending upon where you are going with this, so I'll put four here:
What's the best way to grab/parse command line arguments passed to a Python script?
Implementing a "[command] [action] [parameter]" style command-line interfaces?
How can I process command line arguments in Python?
How do I format positional argument help using Python's optparse?
But the direct answer to your question from the Python docs:
sys.argv -
The list of command line arguments passed to a Python script. argv[0] is the script name (it is operating system dependent whether this is a full pathname or not). If the command was executed using the -c command line option to the interpreter, argv[0] is set to the string '-c'. If no script name was passed to the Python interpreter, argv[0] is the empty string.
To loop over the standard input, or the list of files given on the command line, see the fileinput module.
I'm trying to create a program that can be called from the command line and use keyword arguments in python 2.6. So far I've tried:
#!/usr/bin/python
def read(foo = 5):
print foo
return 0
if __name__ == '__main__'
read()
When I try to run this from the command line: ./test.py the program prints 5 as expected. Is there a way to use ./test.py foo=6? I want to preserve the keyword arguments.
It seems like a simple question, but I haven't found a good source for this.
python has built in library to help you achieve passing command line arguments to a script
argparse. THe usage is a little different then what you are describing in your question though...
On a basic level you can access all command line arguments by sys.argv, which will be a list of arguments
Sorry should have mentioned the python 2.6 library is called optparse
Something like this?
if __name__ == '__main__':
kwargs = dict(x.split('=', 1) for x in sys.argv[1:])
read(**kwargs)
That said, argparse and optparse are probably going to give you something more robust and more natural for someone used to the commandline. (Not to mention, supporting arguments of types other than string.)
Oh, and if what you're really after is just interactive use of your function, use the interactive interpreter; either python or ipython. You'd need to put the code into a file ending in .py and import it, then you could just call it.
A less usual, but very interesting alternative is docopt: a library that generates an argument parser from the help message that you write for your program (on github).