Reputation: 464
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?
Upvotes: 1
Views: 5426
Reputation: 46
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))
Upvotes: 0
Reputation: 140286
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.
Upvotes: 3