簡體   English   中英

Python 子進程無法捕獲 Windows 程序的輸出

[英]Python subprocess cannot capture output of Windows program

使用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捕獲任何內容。 我很高興在評論中重試這些命令中的任何一個。

我猜這與程序附加到外殼有關。

這是程序用來輸出的程序集( 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 答案給出了如何解決它的大綱。 如果其他人有這個問題,我已經在 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

對我來說更好的解決方案是使用相同的StdHandleWriteConsoleA更改為WriteFile

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

您是否也嘗試捕獲 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

我認為我沒有足夠的代表來建議一個問題可能重復,也沒有評論,所以我將此作為答案發布,因為盡管 douggard 的答案使我在思考上走上了正確的道路,但它實際上並沒有奏效就我而言,我很難找到可行的解決方案。

這里有一個捕獲 CONOUT 並為我工作的答案: https ://stackoverflow.com/a/38749458/1675668

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM