将stdout传递到两个不同的地方?

时间:2014-12-12 10:23:05

标签: python windows python-2.7 tkinter subprocess

想法是在子进程行中运行命令,将整个输出发送到一个tkinter文本小部件(outputText)并搜索输出,如果适用,则将信息写入另一个tkinter文本小部件(inputText)。请参阅此代码部分:

if (v1.get()) == 1:
    reply = subprocess.Popen("c:\delprof2\DelProf2.exe /c:" + machineName, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    data, error = reply.communicate()
    outputText.insert("end", data)
    for line in reply.stdout:
        if line.strip() == "The following user profiles match the deletion criteria:":
        inputText.insert("end", machineName + " has matching profiles" + "\n")

和本节:

if (v1.get()) == 1:
    reply = subprocess.Popen("c:\delprof2\DelProf2.exe /c:" + machineName, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    for line in reply.stdout:
        if line.strip() == "The following user profiles match the deletion criteria:":
        inputText.insert("end", machineName + " has matching profiles" + "\n")
    data, error = reply.communicate()
    outputText.insert("end", data)

正如您所看到的,除了线条的运行顺序之外,它们是相同的。在这两个示例中,只会执行代码的第一部分,而不会执行第二部分。就像线条在stdout上战斗一样,无论哪个都先跑了! 我需要改变什么来让它们都起作用?

谢谢!

2 个答案:

答案 0 :(得分:1)

两个代码示例都不正确。 for line in process.stdoutprocess.communicate()都使用所有子进程'stdout。

两个方法都会阻塞,直到子进程完成写入 - 它可能会冻结您的GUI - 您应该将代码放入单独的(来自GUI)线程或使用异步I / O.这是代码示例,演示如何get subprocess' output using a background thread。这是the same using async. I/O (*nix)

要一次将输出插入两个地方,您可以修改the multithreaded code example中的update()方法,以便在必要时为每行和小部件调用.insert()

注意:如果要重定向stdout / stderr(如代码中那样),则需要同时读取两个流,否则可能出现死锁。如果你需要stderr然后创建一个单独的线程来读取(类似于stdout的线程)或者用.createfilehandler()方法注册一个读处理程序(仅限* nix)。

答案 1 :(得分:0)

因为正如J.F. Sebastian所说,.stdout& .communicate()使用进程' stdout,你的问题类似于使用python生成器:你只能得到进程'输出一次。

解决方案?如果我正确理解你的问题,那么你只想使用该过程的输出两次。在这种情况下,将其分配给变量一次,并根据需要多次调用该变量。 e.g:

第1节:

if (v1.get()) == 1:
  reply = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  data, error = reply.communicate()
  outputText.insert("end", data)
  for line in data:  # the stdout is in data! reply.stdout won't be useful here since you called .communicate()
    # do stuff with data

或者,在第2节:

if (v1.get()) == 1:
  reply = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  data = reply.stdout  # you can call this variable as many times as you want and it will return the same data
  for line in data:
    inputText.insert("end", machineName + " has matching profiles" + "\n")
  # data, error = reply.communicate() <-- this would reset data to ''
  outputText.insert("end", data)

以下是重置数据的示例:

x = subprocess.Popen("echo ok", stdout=subprocess.PIPE, shell=True)
for line in x.stdout:
  print line
  # this prints "ok", as expected
tup = x.communicate()
tup == ('', None)  # This is True, since x.stdout consumed the output

这会回答你的问题吗?