Ronald Dregan
Ronald Dregan

Reputation: 183

process.call and cmd.exe

I am trying to make a repeated call on the windows command line from my python code. For each fine in a directory, I need to run a command, and wait for it to finish.

try:
    directoryListing = os.listdir(inputDirectory)
    for infile in directoryListing:
        meshlabString = #string to pass to command line
        os.system(meshlabString)

except WindowsError as winErr:
    print("Directory error: " + str((winErr)))

I have been reading online, and it seems the preferred way to do this is with subprocess.call(), but I cannot figure out how to run cmd.exe through subprocess.call(). It kind of works right now using os.system(), but it gets caught up trying to run a bunch of processes at once, and dies. If someone could provide me a few lines of code on how to run a command on the windows command line, and if subprocess.wait() is the best way to wait.

Upvotes: 1

Views: 490

Answers (2)

Robert
Robert

Reputation: 8767

You have two options, subprocess.Popen and subprocess.call. The main difference is that by default Popen is non-blocking, whereas call is blocking. This means that you can interact with Popen while its running, but you cannot with call. You must wait for the process to complete with call, which you can modify Popen to run in the same manner by utilizing wait().

call itself is just a wrapper around Popen as shown in the source:

def call(*popenargs, timeout=None, **kwargs):
    """Run command with arguments.  Wait for command to complete or
    timeout, then return the returncode attribute.

    The arguments are the same as for the Popen constructor.  Example:

    retcode = call(["ls", "-l"])
    """
    with Popen(*popenargs, **kwargs) as p:
        try:
            return p.wait(timeout=timeout)
        except:
            p.kill()
            p.wait()
            raise

Using call:

import os
from subprocess import call
from shlex import split

try:
    directoryListing = os.listdir(inputDirectory)
    for infile in directoryListing:
        meshlabString = #string to pass to command line
        call(split(meshlabString)) # use split(str) to split string into args

except WindowsError as winErr:
    print("Directory error: " + str((winErr)))

Upvotes: 1

mgilson
mgilson

Reputation: 309821

with subprocess, you have a few options. The easiest is call:

import shlex
return_code=subprocess.call(shlex.split(meshlabString))

shlex takes the string and splits it into a list the way the shell would split it. in other words:

shlex.split("this 'is a string' with 5 parts") # ['this', 'is a string', 'with', '5', 'parts]

You could also do:

return_code=subprocess.call(meshlabString,shell=True)

but this way is a security risk if meshlabString is untrusted. Ultimately, subprocess.call is just a wrapper on the subprocess.Popen class, provided for convenience, but it has the functionality that you want here.

Upvotes: 1

Related Questions