Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

loop over a batch script that does not terminate

I m trying to execute several batch-scripts in a python loop. However the said bat-scripts contain cmd /K and thus do not "terminate" (for lack of a better word). Therefore python calls the first script and waits forever...

Here is a pseudo-code that gives an idea of what I am trying to do:

import subprocess

params = [MYSCRIPT, os.curdir]    
for level in range(10):
    subprocess.call(params)  

My question is: "Is there a pythonic solution to get the console command back and resume looping?"


EDIT: I am now aware that it is possible to launch child processes and continue without waiting for them to return, using

Popen(params,shell=False,stdin=None,stdout=None,stderr=None,close_fds=True)

However this would launch my entire loop almost simultaneously. Is there a way to wait for the child process to execute its task and return when it hits the cmd /K and becomes idle.

like image 634
snake_charmer Avatar asked Dec 07 '16 14:12

snake_charmer


1 Answers

There is no built in way, but it's something you can implement.

Examples are with bash since I don't have access to a Windows machine, but should be similar for cmd \K

It might be as easy as:

import subprocess

# start the process in the background
process = subprocess.Popen(
    ['bash', '-i'],
    stdout=subprocess.PIPE,
    stdin=subprocess.PIPE
)

# will throw IO error if process terminates by this time for some reason
process.stdin.write("exit\n")
process.wait()

This will send an exit command to the shell, which should be processed just as the script terminates causing it to exit ( effectively canceling out the \K )

Here's a more elaborate answer in case you need a solution that checks for some output:

import subprocess

# start the process in the background
process = subprocess.Popen(
    ['bash', '-i'],
    stdout=subprocess.PIPE,
    stdin=subprocess.PIPE
)

    # Wait for the process to terminate
    process.poll()
    while process.returncode is None:
        # read the output from the process
        # note that can't use readlines() here as it would block waiting for the process
        lines = [ x for x in process.stdout.read(5).split("\n") if x]
        if lines:
            # if you want the output to show, you'll have to print it yourself
            print(lines )
            # check for some condition in the output
            if any((":" in x for x in lines)):
                # terminate the process
                process.kill()
                # alternatively could send it some input to have it terminate
                # process.stdin.write("exit\n")
        # Check for new return code
        process.poll()

The complication here is with reading the output, as if you try to read more than is available, the process will block.

like image 118
Alpar Avatar answered Oct 12 '22 18:10

Alpar