Question

Does anybody know what is the equivalent of batch script's %* in python ?

Clarification: in a batch file %* is all parameters specified in the command line -- this is very useful if you want to forward the parameters to another program.

My Problem is that I want to convert one batch call to a python call :

Batch call is :

trial.bat %*


what is the equivalent python call ?(P.S. I know I can just go through the whole sys.argv list and append parameters in some string and pass that to the batch file, but I am looking for a simpler solution here)

I tried following :

os.system('trial.bat '+sys.argv)
os.system('trial.bat '+sys.argv[1:])

But that is not working. I tried similar thing using argparse as well. Its not working either. Please help.

Was it helpful?

Solution

sys.argv[1:] is pretty close. The thing is that argv is a list of arguments, and [1:] is a slice of a list, which is again a list. If you want a string with all arguments combined, you can join them again:

os.system('trial.bat ' + ' '.join(sys.argv[1:]))

Or even better, you use the subprocess module which method’s accept a list of arguments:

subprocess.check_call(['trial.bat'] + sys.argv[1:])

Subprocess is much more flexible when handling parameters and will also behave similar to the parsing in argv. As an example, when calling a script with the arguments foo "hello world" bar, argv will contain this:

>>> sys.argv[1:]
['foo', 'hello world', 'bar']

Now if we were to simply join this list, we would get a single string

>>> ' '.join(sys.argv[1:])
'foo hello world bar'

As you can see, the information of the compound argument hello world is lost, resulting in a completely different meaning.

When using subprocess however, you keep your list and subprocess will automatically make sure to pass these arguments correctly to the called program. So the called program will be able to get hello world as a combined argument too.

OTHER TIPS

You want subprocess.Popen (or one of it's convenience wrappers):

import subprocess
import sys
process = subprocess.Popen(['trial.bat'] + sys.argv[1:])
process.wait()

It's definitely preferred to os.system. The advantage here is that commandline arguments which may need to be quoted to keep their meaning effectively stay quoted. Additionally, this alternative is probably safer than os.system since it avoids creating a subshell.

If you want to use os.system, you need to put the command line back together manually. Python has already parsed the command line apart into separate arguments (or MSVCRT has done it on Python's behalf). This means you need to not just concatenate them back together, but also quote them appropriately.

There is nothing in the stdlib that handles the "quote them appropriately" exactly the way MSVCRT wants. That's partly because Windows quoting is actually ambiguous; there are some cases where it is impossible to round-trip things. But, for simple cases, either POSIX-style quoting (with shlex.quote) or just sticking explicit quotes around each argument will work. So, either of these:

args = ' '.join(shlex.quote(arg) for arg in [program] + sys.argv[1:])
args = ' '.join('"{}"'.format(arg) for arg in [program] + sys.argv[1:])

Then:

os.system(args)

But using subprocess is better than os.system. One reason is that you don't have to fiddle with quoting things; you can just do this:

subprocess.check_call([program] + sys.argv[1:], shell=True)

Someone still needs to put the list of arguments back together in a string so it can be passed to the shell, but now that "someone" is the subprocess module rather than your code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top