pythonwindowscmdsubprocess

Interact with the Windows CMD in python


I am trying to open a windows CMD and read/write into it. I managed to open the CMD with this command:

import subprocess
proc = subprocess.Popen('cmd.exe')

To write into the CMD console, I tried the solution from this question:

proc.communicate('cd Documents')

This line automatically closed the CMD, so i wasn't able to see if it worked.

How can I read and write into the Windows CMD?


Solution

  • communicate sends the contents of the buffer to standard input then closes the input pipe, which ends up terminating the process. So you cannot do something interactive with that.

    Moreover, you have to pass stdin argument to Popen or by default nothing is redirected.

    import subprocess
    proc = subprocess.Popen('cmd.exe',stdin=subprocess.PIPE)
    

    now you can write lines to proc.stdin (don't forget line terminators & binary prefix for python 3 compat.) and see what happens

    proc.stdin.write(b"cd Documents\n")
    

    (okay, you could have used cwd="Documents" for that one, but that's for the sake of the example)

    In the example, output is not redirected. Which means that you'll see the output in the current console. Don't forget to close standard input or that won't work (probably because buffer isn't flushed and/or pipe is broken when python quits). Then wait for process to finish with wait()

    Complete example:

    import subprocess
    proc = subprocess.Popen('cmd.exe',stdin=subprocess.PIPE)
    proc.stdin.write(b"cd ..\n")
    # do some stuff in between...
    proc.stdin.write(b"cd\n")
    proc.stdin.close()
    proc.wait()
    

    on my computer it prints (excuse my french)

    Microsoft Windows [version 6.1.7601]
    Copyright (c) 2009 Microsoft Corporation. Tous droits réservés.
    
    L:\so>cd ..
    
    L:\>cd
    L:\
    

    if you want the process not to terminate, you could use some more tricks: import subprocess,time

    proc = subprocess.Popen('cmd.exe',stdin=subprocess.PIPE)
    proc.stdin.write(b"cd ..\n")
    proc.stdin.write(b"cd\n")
    proc.stdin.flush()
    time.sleep(1)
    input("press return")
    proc.stdin.write(b"cd\n")
    proc.stdin.flush()
    proc.stdin.close()
    proc.wait()
    

    this sends commands, flushes standard input (but doesn't close it) then waits for the messages to print, and asks for a key to be pressed. You can send more commands after that, as long as you flush each time, and close in the end.