why does python.subprocess hang after proc.communicate()?

后端 未结 3 1752
死守一世寂寞
死守一世寂寞 2020-12-15 07:11

I\'ve got an interactive program called my_own_exe. First, it prints out alive, then you input S\\n and then it prints out alive

相关标签:
3条回答
  • 2020-12-15 07:18

    communicate() reads data from stdout and stderr until end-of-file is reached. - It waits until your program quits.

    0 讨论(0)
  • 2020-12-15 07:36

    comunicate will only run once and then will close the pipe, therefore if you want to send several commands to it you need to send one after the other in the same string.

    Here is an example that worked for me after some investigation, trying threads, subprocess32, stdin.write, stdout.read etc etc. This information is not in the official python reference information for communicate: https://docs.python.org/2/library/subprocess.html

    The only place where I found this out was here: Python subprocess communicate kills my process

    Here is the code, it is simple, no threads, no subprocess32, works on linux and windows. Yes you have to know how many times to send commands to the other process but in general you do know that. On top of this you can add threads, cwd, shell=True or anything else you may want but this is the simplest case:

    def do_commands(self, cmd, parms):
        proc = subprocess.Popen(cmd,  stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE )
    
        # wait for the process to terminate
        out, err = process.communicate(cmd_parms)
        errcode = process.returncode
    
        return errcode, out, err
    

    So for example if you want to send multiple carriage returns (\n) to the application being called and the a param in the middle (interactively mind you) you would call it something like this:

    cmd_parms = "\n\n\n\n\nparm\n\n"
    
    errcode, out, err = do_commands(command, cmd_parms)
    

    Hope it helps.

    0 讨论(0)
  • 2020-12-15 07:40

    From the docs for communicate:

    Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate.

    So after communicate() runs, the process has been terminated.

    If you want to write and read without waiting for the process to stop:

    • Don't ever use shell=True - it needlessy invokes a shell to in turn call your program, so there will be another process between you and your program. That has lots of unpleasant side-effects. The default is shell=False so you should stick with that. Change your Popen line to:

      p = subprocess.Popen(["./AO_FelixStrategy_UnitTest",
                            "--bats", "31441", "--chix", "12467",
                            "--enxutp", "31884", "--turq", "26372",
                            "--symbol", "SOGN", "--target_date", '2009-Oct-16'],
                           stdin=subprocess.PIPE, 
                           stdout=subprocess.PIPE)
      
    • Use p.stdin.write to write to the process. Use p.stdout.read to read from it.

    • Calling p.stdout.read if there's nothing to read will block. Calling p.stdin.write if the write buffer is full will block. So you have to make sure you have something to read/write - you do that on unix OS by using select. On windows you unfortunately must resort to threads. At least that is what Popen.communicate does internally.
    • If you didn't write AO_FelixStrategy_UnitTest then you have possible additional problems:
      • It could be reading from somewhere else, not standard input. Some programs read directly from the terminal, others use some OS API to read. That means data written to stdin won't go to the program. This is often true for password prompts.
      • Remember that you have to account for AO_FelixStrategy_UnitTest buffers. By default standard C PIPE communication is buffered so you may not see any output until after you've closed the input side (by doing p.stdin.close(). Unless AO_FelixStrategy_UnitTest flushes the output periodically.

    Here's some example code, based on what you describe. It could work depending on how AO_FelixStrategy_UnitTest was developed:

    p = subprocess.Popen(["./AO_FelixStrategy_UnitTest",
                          "--bats", "31441", "--chix", "12467",
                          "--enxutp", "31884", "--turq", "26372",
                          "--symbol", "SOGN", "--target_date", '2009-Oct-16'],
                         stdin=subprocess.PIPE, 
                         stdout=subprocess.PIPE)
    output = p.communicate('S\nL\n')[0]
    print output
    
    0 讨论(0)
提交回复
热议问题