为什么python。子流程后挂proc.communicate()?

时间:2021-12-30 20:58:35

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 again. Finally you input L\n. It does some processing and exits.

我有一个名为my_own_exe的交互式程序。首先,它打印出生命,然后输入S\n,然后再打印出来。最后你输入L \ n。它执行一些处理和退出。

However, when I call it from the following python script, the program seemed to hang after printing out the first 'alive'.

然而,当我从下面的python脚本中调用它时,程序似乎在打印出第一个“alive”后挂起了。

Can anyone here tell me why this is happening?

有人能告诉我为什么会这样吗?

// after reading the follow ups (thank you guys), i modified the code as following:

//在阅读完后续文章后(谢谢各位),我修改了以下代码:

import subprocess
import time

base_command = "./AO_FelixStrategy_UnitTest --bats 31441 --chix 12467 --enxutp 31884 --turq 26372 --symbol SOGN --target_date " + '2009-Oct-16'
print base_command

proc2 = subprocess.Popen(base_command, shell=True , stdin=subprocess.PIPE,)

time.sleep(2);
print "aliv"
proc2.communicate('S\n')

print "alive"
time.sleep(6)

print "alive"
print proc2.communicate('L\n')
time.sleep(6)

the program now goes well with the first input 'S\n', but then stopped, and I the second 'L\n' is kinda ignored.

这个程序现在和第一个输入'S\n'很好,但是后来停止了,我第二个'L\n'被忽略了。

Can anyone give me an idea why it's like this?

谁能告诉我为什么会这样?

3 个解决方案

#1


23  

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.

与进程交互:将数据发送到stdin。从stdout和stderr读取数据,直到文件结束。等待进程终止。

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:

    不要使用shell=True—它需要调用shell来调用您的程序,因此在您和您的程序之间将会有另一个过程。这有许多令人不快的副作用。默认的是shell=False,所以您应该继续使用它。将你的Popen线改为:

    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.

    使用p.stdin。写信给这个过程。使用p.stdout。读它。

  • 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.
  • 调用p.stdout。如果没有什么可读的,请阅读。调用p.stdin。如果写入缓冲区已满,则写入。所以你必须确保你有一些东西可以读/写——你可以在unix操作系统上使用select。不幸的是,在windows上你必须求助于线程。至少,这是popen.com内部的交流方式。
  • 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.
    • 它可以是从其他地方读取,而不是标准输入。有些程序直接从终端读取,有些则使用一些OS API来读取。这意味着写入stdin的数据不会进入程序。对于密码提示,这通常是正确的。
    • 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.
    • 请记住,您必须考虑到AO_FelixStrategy_UnitTest缓冲区。默认标准C管道通信是缓冲的,因此在关闭输入端之前,您可能不会看到任何输出(通过做p.stdin.close()。除非AO_FelixStrategy_UnitTest定期刷新输出。
  • 如果您没有编写AO_FelixStrategy_UnitTest,那么您可能会遇到其他问题:它可能是从其他地方读取的,而不是标准输入。有些程序直接从终端读取,有些则使用一些OS API来读取。这意味着写入stdin的数据不会进入程序。对于密码提示,这通常是正确的。请记住,您必须考虑到AO_FelixStrategy_UnitTest缓冲区。默认标准C管道通信是缓冲的,因此在关闭输入端之前,您可能不会看到任何输出(通过做p.stdin.close()。除非AO_FelixStrategy_UnitTest定期刷新输出。

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

下面是一些示例代码,基于您所描述的。它可以工作取决于如何开发AO_FelixStrategy_UnitTest:

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

#2


3  

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

通信()从stdout和stderr读取数据,直到到达文件结束。-它等待直到你的程序退出。

#3


0  

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.

comunicate只运行一次,然后关闭管道,因此如果您想要发送几个命令,您需要在同一字符串中发送一个。

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

这里有一个例子,在一些调查之后,尝试线程,subprocess32, stdin。写,stdout。这些信息不是在官方的python参考信息中用于通信:https://docs.python.org/2/library/subprocess.html。

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

我在这里发现这个的唯一的地方是:Python子进程通信杀死了我的进程。

In any case here is the code, 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:

在任何情况下,都是代码,简单,没有线程,没有subprocess32,在linux和windows上工作。是的,你必须知道向另一个进程发送命令的次数,但一般情况下你知道。除此之外,您还可以添加线程、cwd、shell=True或其他您想要的东西,但这是最简单的情况:

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:

例如,如果你想要发送多个回车(\n)到被调用的应用程序和中间的一个param(交互式地提醒你),你可以这样称呼它:

cmd_parms = "\n\n\n\n\nparm\n\n"

errcode, out, err = do_commands(command, cmd_parms)

#1


23  

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.

与进程交互:将数据发送到stdin。从stdout和stderr读取数据,直到文件结束。等待进程终止。

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:

    不要使用shell=True—它需要调用shell来调用您的程序,因此在您和您的程序之间将会有另一个过程。这有许多令人不快的副作用。默认的是shell=False,所以您应该继续使用它。将你的Popen线改为:

    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.

    使用p.stdin。写信给这个过程。使用p.stdout。读它。

  • 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.
  • 调用p.stdout。如果没有什么可读的,请阅读。调用p.stdin。如果写入缓冲区已满,则写入。所以你必须确保你有一些东西可以读/写——你可以在unix操作系统上使用select。不幸的是,在windows上你必须求助于线程。至少,这是popen.com内部的交流方式。
  • 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.
    • 它可以是从其他地方读取,而不是标准输入。有些程序直接从终端读取,有些则使用一些OS API来读取。这意味着写入stdin的数据不会进入程序。对于密码提示,这通常是正确的。
    • 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.
    • 请记住,您必须考虑到AO_FelixStrategy_UnitTest缓冲区。默认标准C管道通信是缓冲的,因此在关闭输入端之前,您可能不会看到任何输出(通过做p.stdin.close()。除非AO_FelixStrategy_UnitTest定期刷新输出。
  • 如果您没有编写AO_FelixStrategy_UnitTest,那么您可能会遇到其他问题:它可能是从其他地方读取的,而不是标准输入。有些程序直接从终端读取,有些则使用一些OS API来读取。这意味着写入stdin的数据不会进入程序。对于密码提示,这通常是正确的。请记住,您必须考虑到AO_FelixStrategy_UnitTest缓冲区。默认标准C管道通信是缓冲的,因此在关闭输入端之前,您可能不会看到任何输出(通过做p.stdin.close()。除非AO_FelixStrategy_UnitTest定期刷新输出。

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

下面是一些示例代码,基于您所描述的。它可以工作取决于如何开发AO_FelixStrategy_UnitTest:

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

#2


3  

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

通信()从stdout和stderr读取数据,直到到达文件结束。-它等待直到你的程序退出。

#3


0  

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.

comunicate只运行一次,然后关闭管道,因此如果您想要发送几个命令,您需要在同一字符串中发送一个。

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

这里有一个例子,在一些调查之后,尝试线程,subprocess32, stdin。写,stdout。这些信息不是在官方的python参考信息中用于通信:https://docs.python.org/2/library/subprocess.html。

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

我在这里发现这个的唯一的地方是:Python子进程通信杀死了我的进程。

In any case here is the code, 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:

在任何情况下,都是代码,简单,没有线程,没有subprocess32,在linux和windows上工作。是的,你必须知道向另一个进程发送命令的次数,但一般情况下你知道。除此之外,您还可以添加线程、cwd、shell=True或其他您想要的东西,但这是最简单的情况:

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:

例如,如果你想要发送多个回车(\n)到被调用的应用程序和中间的一个param(交互式地提醒你),你可以这样称呼它:

cmd_parms = "\n\n\n\n\nparm\n\n"

errcode, out, err = do_commands(command, cmd_parms)