Python子进程无法捕获Windows程序的输出

时间:2017-10-31 15:26:31

标签: python windows winapi cmd subprocess

使用stdout=subprocess.PIPE停止输出进入控制台,但没有捕获任何内容。

>>> import subprocess
>>> proc = subprocess.Popen(['C:\\Users\\me\\program.exe'])
>>> ERROR: please provide an argument
// TRUNCATED USAGE OUTPUT
proc.wait()
0
>>> proc = subprocess.Popen([''C:\\Users\\me\\program.exe''], stdout=subprocess.PIPE)
>>> proc.communicate()
('', None)

我已尝试过stackoverflow上的所有组合。 shell=True没有工作。产生一个子cmd并没有奏效。 subprocess.check_output没有捕获任何内容。我很高兴在评论中重试这些命令。

我猜这与程序附加到shell有关。

这是程序用来输出的程序集(mcall只是一个将内存对齐到16位的宏)。我包含这个的原因是GetStdHandle正在影响事情。

console_write PROC
; rcx   MSG
; rdx   LEN
  prologue
  push    rcx
  push    rdx
  xor     rcx, rcx
  mov     ecx, [stdout]
  mcall   GetStdHandle
  mov     rcx, rax
  xor     rdx, rdx
  pop     r8    ; len
  pop     rdx   ; msg
  push    0
  mov     r9, rsp
  push    0
  mcall   WriteConsoleA
  pop     rcx
  pop     rcx
  epilogue
console_write ENDP

我很难过这个。我在Linux上这么多次这样做了。我对Windows内部的了解不够充分。谢谢!

编辑:我尝试过的其他内容:

管理员(也使用STDERR捕获)

C:\Windows\system32>C:\Python27\python.exe
Python 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:19:30) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> proc = subprocess.Popen(['C:\\Users\\me\\program.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> proc.communicate()
('', '')

STDOUT文件重定向

>>> import os
>>> os.system('C:\\Users\\me\\program.exe > out.txt')
0
>>> f = open('out.txt', 'r')
>>> f.read()
''

STDERR文件重定向

>>> import os
>>> os.system('C:\\Users\\me\\program.exe 2>out.txt')
ERROR: please provide an argument
// TRUNCATED USAGE OUTPUT
0
>>> open('out.txt', 'r').read()
''

命令行捕获失败(禁止输出转到cmd,但没有捕获任何内容)

program.exe > out.txt

3 个答案:

答案 0 :(得分:1)

你是否也试图抓住stderr?

proc = subprocess.Popen([''C:\\Users\\me\\program.exe''], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

<强>更新

您可以尝试在进程运行时逐行读取输出,例如:

p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
    retcode = p.poll()
    print p.stdout.readline()
    if retcode is not None:
        break

答案 1 :(得分:1)

一位同事指出了这个问题。事实证明WriteConsole无法重定向到文件,它只能用于控制台句柄。 [1] [2]

这个StackOverflow answer给出了如何解决它的大纲。如果其他人有这个问题,我已经用Python实现了它。

import win32console
import subprocess
import msvcrt
import os

ccsb = win32console.CreateConsoleScreenBuffer()
fd = msvcrt.open_osfhandle(ccsb, os.O_APPEND)
proc = subprocess.Popen(['C:\\Users\\me\\program.exe'], stdout=fd)
proc.wait()
ccsb.ReadConsoleOutputCharacter(100, win32console.PyCOORDType(0,0)) # reads 100 characters from the first line

对我来说,更好的解决方案是使用相同的WriteConsoleAWriteFile更改为StdHandle

console_write PROC
; rcx   MSG
; rdx   LEN
  prologue
  push    rcx
  push    rdx
  xor     rcx, rcx
  mov     ecx, [stdout]
  mcall   GetStdHandle
  mov     rcx, rax
  ; Write File
  pop     r8    ; len
  pop     rdx   ; msg
  ; unalign for odd number of pushed args
  mov     rbx, rsp
  sub     rbx, 8        
  and     rbx, 0Fh
  sub     rsp, rbx
  ; args
  mov     rcx, rax        ; handle
  xor     r9, r9
  push    0               ; 1 arg (ununaligns)
  sub     rsp, 20h        ; shadow 
  call    WriteFile
  add     rsp, 28h        ; shadow + arg
  add     rsp, rbx        ; realign
  epilogue
console_write ENDP

答案 2 :(得分:1)

我认为我没有足够的代表来建议一个问题可能是重复的,也没有评论,所以我将此作为答案发布,因为尽管 douggard 的回答使我在思考上走上了正轨,但它没有t 实际上在我的情况下有效,而且我很难找到可行的解决方案。

这里有一个捕获 CONOUT 并为我工作的答案:https://stackoverflow.com/a/38749458/1675668