使用 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

最佳答案

一位同事指出了这个问题。结果证明 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

10-08 04:58