python - Executable called via subprocess.check_output prints on console but result is not returned -


on windows machine, i'm trying call external executable python , gather outputs further processing. because local path variable has set before calling executable, created batch script

  • first calls script set %path% ,
  • then calls executable parameters given it.

the *.bat file looks this:

@echo off call set_path.bat @echo on executable.exe %* 

and python code this:

print("before call"); result = subprocess.check_output([batfile, parameters], stderr=subprocess.stdout, shell=true); print("after call");  print("------- ------- ------- printing result ------- ------- ------- "); print(result); print("------- ------- ------- /printing result ------- ------- ------- "); 

now, technically, works. executable called intended parameters, runs, finishes , produces results. know this, because mockingly displayed in console in python script running.

however, result string contains batch script returns, not executables outputs:

before call

hello? yes, executable.exe

after call

------- ------- ------- printing result ------- ------- -------

c:\users\me\documents\pythonscript\execute\executable.exe "para1|para2|para3"

------- ------- ------- /printing result ------- ------- -------

the subprocess.check_output command somehow prints intended output console, returns contains batch file's outputs after @echo on again.

how can access , save executable's output string further work?

or have somehow modify batch file catch , print output, end upt in check_output's results? if so, how go doing that?

if program writes directly console (e.g. opening conout$ device) instead of process standard handles, option read console screen buffer directly. make simpler, start new, empty screen buffer. create, size, initialize, , activate new screen buffer via following functions:

make sure request generic_read | generic_write access when calling createconsolescreenbuffer. you'll need read access later in order read contents of screen.

specifically python, use ctypes call functions in windows console api. also, if wrap handle c file descriptor via msvcrt.open_osfhandle, can pass stdout or stderr argument of subprocess.popen.

the file descriptor or handle screen buffer can't read directly via read, readfile, or readconsole. if have file descriptor, underlying handle via msvcrt.get_osfhandle. given screen buffer handle, call readconsoleoutputcharacter read screen. read_screen function in sample code below demonstrates reading beginning of screen buffer cursor position.

a process needs attached console in order use console api. end, i've included simple allocate_console context manager temporarily open console. useful in gui application, isn't attached console.

the following example tested in windows 7 , 10, in python 2.7 , 3.5.

ctypes definitions

import os import contextlib import msvcrt import ctypes ctypes import wintypes  kernel32 = ctypes.windll('kernel32', use_last_error=true)  generic_read  = 0x80000000 generic_write = 0x40000000 file_share_read  = 1 file_share_write = 2 console_textmode_buffer = 1 invalid_handle_value = wintypes.handle(-1).value std_output_handle = wintypes.dword(-11) std_error_handle = wintypes.dword(-12)  def _check_zero(result, func, args):     if not result:         raise ctypes.winerror(ctypes.get_last_error())     return args  def _check_invalid(result, func, args):     if result == invalid_handle_value:         raise ctypes.winerror(ctypes.get_last_error())     return args  if not hasattr(wintypes, 'lpdword'): # python 2     wintypes.lpdword = ctypes.pointer(wintypes.dword)     wintypes.psmall_rect = ctypes.pointer(wintypes.small_rect)  class coord(ctypes.structure):     _fields_ = (('x', wintypes.short),                 ('y', wintypes.short))  class console_screen_buffer_infoex(ctypes.structure):     _fields_ = (('cbsize',               wintypes.ulong),                 ('dwsize',               coord),                 ('dwcursorposition',     coord),                 ('wattributes',          wintypes.word),                 ('srwindow',             wintypes.small_rect),                 ('dwmaximumwindowsize',  coord),                 ('wpopupattributes',     wintypes.word),                 ('bfullscreensupported', wintypes.bool),                 ('colortable',           wintypes.dword * 16))     def __init__(self, *args, **kwds):         super(console_screen_buffer_infoex, self).__init__(                 *args, **kwds)         self.cbsize = ctypes.sizeof(self)  pconsole_screen_buffer_infoex = ctypes.pointer(                                     console_screen_buffer_infoex) lpsecurity_attributes = wintypes.lpvoid  kernel32.getstdhandle.errcheck = _check_invalid kernel32.getstdhandle.restype = wintypes.handle kernel32.getstdhandle.argtypes = (     wintypes.dword,) # _in_ nstdhandle  kernel32.createconsolescreenbuffer.errcheck = _check_invalid kernel32.createconsolescreenbuffer.restype = wintypes.handle kernel32.createconsolescreenbuffer.argtypes = (     wintypes.dword,        # _in_       dwdesiredaccess     wintypes.dword,        # _in_       dwsharemode     lpsecurity_attributes, # _in_opt_   lpsecurityattributes     wintypes.dword,        # _in_       dwflags     wintypes.lpvoid)       # _reserved_ lpscreenbufferdata  kernel32.getconsolescreenbufferinfoex.errcheck = _check_zero kernel32.getconsolescreenbufferinfoex.argtypes = (     wintypes.handle,               # _in_  hconsoleoutput     pconsole_screen_buffer_infoex) # _out_ lpconsolescreenbufferinfo  kernel32.setconsolescreenbufferinfoex.errcheck = _check_zero kernel32.setconsolescreenbufferinfoex.argtypes = (     wintypes.handle,               # _in_  hconsoleoutput     pconsole_screen_buffer_infoex) # _in_  lpconsolescreenbufferinfo  kernel32.setconsolewindowinfo.errcheck = _check_zero kernel32.setconsolewindowinfo.argtypes = (     wintypes.handle,      # _in_ hconsoleoutput     wintypes.bool,        # _in_ babsolute     wintypes.psmall_rect) # _in_ lpconsolewindow  kernel32.fillconsoleoutputcharacterw.errcheck = _check_zero kernel32.fillconsoleoutputcharacterw.argtypes = (     wintypes.handle,  # _in_  hconsoleoutput     wintypes.wchar,   # _in_  ccharacter     wintypes.dword,   # _in_  nlength     coord,            # _in_  dwwritecoord     wintypes.lpdword) # _out_ lpnumberofcharswritten  kernel32.readconsoleoutputcharacterw.errcheck = _check_zero kernel32.readconsoleoutputcharacterw.argtypes = (     wintypes.handle,  # _in_  hconsoleoutput     wintypes.lpwstr,  # _out_ lpcharacter     wintypes.dword,   # _in_  nlength     coord,            # _in_  dwreadcoord     wintypes.lpdword) # _out_ lpnumberofcharsread 

functions

@contextlib.contextmanager def allocate_console():     allocated = kernel32.allocconsole()     try:         yield allocated     finally:         if allocated:             kernel32.freeconsole()  @contextlib.contextmanager def console_screen(ncols=none, nrows=none):     info = console_screen_buffer_infoex()     new_info = console_screen_buffer_infoex()     nwritten = (wintypes.dword * 1)()     hstdout = kernel32.getstdhandle(std_output_handle)     kernel32.getconsolescreenbufferinfoex(            hstdout, ctypes.byref(info))     if ncols none:         ncols = info.dwsize.x     if nrows none:         nrows = info.dwsize.y     elif nrows > 9999:         raise valueerror('nrows must 9999 or less')     fd_screen = none     hscreen = kernel32.createconsolescreenbuffer(                 generic_read | generic_write,                 file_share_read | file_share_write,                 none, console_textmode_buffer, none)     try:         fd_screen = msvcrt.open_osfhandle(                         hscreen, os.o_rdwr | os.o_binary)         kernel32.getconsolescreenbufferinfoex(                hscreen, ctypes.byref(new_info))         new_info.dwsize = coord(ncols, nrows)         new_info.srwindow = wintypes.small_rect(                 left=0, top=0, right=(ncols - 1),                 bottom=(info.srwindow.bottom - info.srwindow.top))         kernel32.setconsolescreenbufferinfoex(                 hscreen, ctypes.byref(new_info))         kernel32.setconsolewindowinfo(hscreen, true,                 ctypes.byref(new_info.srwindow))         kernel32.fillconsoleoutputcharacterw(                 hscreen, u'\0', ncols * nrows, coord(0,0), nwritten)         kernel32.setconsoleactivescreenbuffer(hscreen)         try:             yield fd_screen         finally:             kernel32.setconsolescreenbufferinfoex(                 hstdout, ctypes.byref(info))             kernel32.setconsolewindowinfo(hstdout, true,                     ctypes.byref(info.srwindow))             kernel32.setconsoleactivescreenbuffer(hstdout)     finally:         if fd_screen not none:             os.close(fd_screen)         else:             kernel32.closehandle(hscreen)  def read_screen(fd):     hscreen = msvcrt.get_osfhandle(fd)     csbi = console_screen_buffer_infoex()     kernel32.getconsolescreenbufferinfoex(         hscreen, ctypes.byref(csbi))     ncols = csbi.dwsize.x     pos = csbi.dwcursorposition     length = ncols * pos.y + pos.x + 1     buf = (ctypes.c_wchar * length)()     n = (wintypes.dword * 1)()     kernel32.readconsoleoutputcharacterw(         hscreen, buf, length, coord(0,0), n)     lines = [buf[i:i+ncols].rstrip(u'\0')                 in range(0, n[0], ncols)]     return u'\n'.join(lines) 

example

if __name__ == '__main__':     import io     import textwrap     import subprocess      text = textwrap.dedent('''\         lorem ipsum dolor sit amet, consectetur adipiscing elit, sed         eiusmod tempor incididunt ut labore et dolore magna aliqua. ut         enim ad minim veniam, quis nostrud exercitation ullamco laboris         nisi ut aliquip ex ea commodo consequat. duis aute irure dolor         in reprehenderit in voluptate velit esse cillum dolore eu         fugiat nulla pariatur. excepteur sint occaecat cupidatat non         proident, sunt in culpa qui officia deserunt mollit anim id est         laborum.''')      cmd = ("python -c \""            "print('piped output');"            "conout = open(r'conout$', 'w');"            "conout.write('''%s''')\"" % text)      allocate_console() allocated:         console_screen(nrows=1000) fd_conout:             stdout = subprocess.check_output(cmd).decode()             conout = read_screen(fd_conout)             io.open('result.txt', 'w', encoding='utf-8') f:                 f.write(u'stdout:\n' + stdout)                 f.write(u'\nconout:\n' + conout) 

output

stdout: piped output  conout: lorem ipsum dolor sit amet, consectetur adipiscing elit, sed eiusmod tempor incididunt ut labore et dolore magna aliqua. ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 

Comments