1

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?

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

9 Comments

I tried your code and it didn't work for my. The console still closed after the line: proc.stdin.write(b"cd Documents\n")
try the complete example
I tried your complete example but it still closed the CMD: gyazo.com/f197465aedcb2de117af3fca1f258c35 (GIF)
of course it closes the CMD. But after performing the job. let me edit.
Ah okey I see. I understood the proc.wait() as the line which leads the to CMD to stay open. Similair like in C# console.ReadKey() .
|
0

This might be of help ! Simple CMD Python Interface for executing sequential commands:

import subprocess class CmdInterface: def __init__(self,nude=True,rm_boilerplate=True,end_signal="cmd_end_command_signal",log_mode=False): self.end_command_signal=end_signal self.nude=nude self.process = subprocess.Popen("cmd", stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True, bufsize=1) self.lock=False self.command_count=0 self.log_mode=log_mode self.log=[] if rm_boilerplate==True: #just an empty first command to clear the boiler plate for the next ones, this is not added in the command count #TODO MAKE SOMETHING THAT DOESNT INJECT A NEW COMMAND self.send_command("@echo.") def __del__(self): # Clean up self.process.stdin.close() self.process.terminate() self.process.wait() def kill(self): # Clean up self.process.stdin.close() self.process.terminate() self.process.wait() def send_command(self,command): #multithreading prevention while True: if self.lock==False: break self.lock=True self.command_count+=1 # Define a unique signal to indicate the end of a command's output end_command_signal = self.end_command_signal extension=f"&& echo {end_command_signal}" command_with_signal = f"{command} {extension}\n" self.process.stdin.write(command_with_signal) self.process.stdin.flush() # Read output until the end signal is detected output = [] cnt=0 while True: line = self.process.stdout.readline() if end_command_signal in line: cnt+=1 if cnt==2: break # Stop reading after detecting the end signal if self.nude==True: output.append(line.replace(extension,"")) else: output.append(line) if self.log_mode==True: self.log+=output self.lock=False return output def get_log(self): return self.log.copy() def turn_on_logging(self): self.log_mode=True def turn_off_logging(self): self.log_mode=False def get_command_count(self): return int(self.command_count) 

Usage example:

from CmdInterface import CmdInterface # ^^^ replace with where file is located/named # Initialize cmd=CmdInterface() # Send commands and capture outputs output_hello_world = cmd.send_command( "echo Hello, World!") output_dir = cmd.send_command( "dir") output_dir2 = cmd.send_command( "cd ..") output_dir3 = cmd.send_command("dir") # Output results print("Output of 'Hello, World!':", ''.join(output_hello_world)) print("Output of 'dir':", ''.join(output_dir)) print("Output of 'dir2':", ''.join(output_dir2)) print("Output of 'dir3':", ''.join(output_dir3)) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.