What's the problem with executing commands in Windows CMD from Python? - python

I'm having huge trouble with passing commands to CMD from Python.
First, I open a CMD process:
cmdprocess = subprocess.Popen("cmd",
stdin = subprocess.PIPE,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE)
Then, I do something, for example:
for i in range(500):
#time.sleep(1)
command = ("dir > " + os.path.join("C:\\", str(i)) + "\r\n").encode("utf-8")
print(command)
cmdprocess.stdin.write(command)
So this is supposed to create 500 small text files in a folder. I tested it in Python 3.2 x64 and 3.2 x86 and the result for both is: it counts up to about 250-350 in the Python shell, and then just stops. No error, nothing. There are then the files 1-80 in the specified folder.
Now, I thought that maybe Python is too fast and so had it sleep(1) for 1 second between the commands. Now, it counts up to about 200 before the first file appears in the folder! and then stops at about 270.
What happens here and how can I force CMD to execute a command immediately?

Are you handling the output in the PIPES? They might be filling. If you fill up the stdout or stderror buffers from the process, it will stop execution.

I think you'd better to use pywin32 package. there are win32pipe and win32process modules.
I also had same issue but I could not resolve it without pywin32-site-package...
So now I am using them... If you need sample code and you're using windows, I will attach it.
if you mean linux... it's same but you need another one like IO select.

Related

How to run cmd.exe in python

I'm trying to port the following c# code into Python. It firstly defines a new process and then runs a windows prompt command (cmd.exe). After that, it executes a command in the prompt and when an external event occurs, it closes the prompt.
//Start the prompt - when an event occured
Process winShell = new Process();
winShell.StartInfo.FileName = "cmd.exe";
winShell.StartInfo.RedirectStandardInput = true;
winShell.Start();
//Execute a command in the prompt
winShell.StandardInput.WriteLine("cd " + projectDirectory);
//Close it - when an event occured
winShell.StandardInput.Flush();
winShell.StandardInput.Close();
winShell.WaitForExit();
I read that for Python 3 (my version 3.7), It is recommended to use subprocess. Unfortunately, I feel a bit confused about which of the function to use. I found call, run and Popen, but I didn't understand how to use them.
I wrote the following lines, but they don't produce any visible result.
import subprocess
subprocess.run(['cmd.exe'])
First of all, I would like that the shell appears and than to write some commands in it. Finally, I want to close it.
Use subprocess.Popen() like this. Each API matches to the corresponding C# API almost 1:1.
p = subprocess.Popen(['cmd.exe'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
text=True)
p.stdin.write('dir\n')
p.stdin.close()
print(p.stdout.read())
p.wait()
p.stdout.close()
Other API's such as run(), call(), etc are wrappers for Popen(). For example, the above code is equivalent to this one line.
print(subprocess.run(['cmd.exe'], capture_output=True, text=True, input = 'dir\n').stdout)

How to use Python subprocess to write multiple inputs into custom exe program

I am trying to open a executable that opens a HEC .dss database file. However, I can only seem to get it to read one argument after opening the exe and then it doesn't read anything else. Is there any way to force it to keep inserting commands.
This exe has some unique features to it, which include that the first command asks what DSS file you are going to read. Then you can input a command to create the output txt file that it will write to for the rest of the commands. What I've been able to do so far is to start the program and run one command into the exe (the mydss variable). However, after that first command is read, none of the other commands are used in the command prompt. I feel like I'm missing something here. Here is the code:
##Testing on how to run and use the DSSUTL program
import subprocess
from subprocess import PIPE, STDOUT
DSSUTL = "C:\Users\sduncan\Documents\HEC-DSS\HEC-DSSVue-2_0_1\FromSivaSel\DSSUTL.exe"
mydss = "C:\Users\sduncan\Documents\HEC-DSS\HEC-DSSVue-2_0_1\FromSivaSel\\forecast.dss"
firstLine = "WR.T TO=PythonTextOutput.txt"
commandLine = "WR.T B=SHAVER RESERVOIR-POOL C=FLOW-IN E=1HOUR F=10203040"
myList = [firstLine, commandLine]
ps = subprocess.Popen([DSSUTL, mydss, myList[1], myList[0]], shell=True)
I've also tried including stdin=subprocess.PIPE, but that only leads to the exe opening and it is blank (when I open it with the code above I can read it and see that the mydss variable was read correctly). When I used stdout or sterr, the program only opens and closes.
I've also tried using the code when the stdin=PIPE was turned on with:
ps.stdin.write(myList[1])
ps.stdin.write(myList[0])
ps.communicate()[0]
However, it did not read anything in the program. This program runs like a command prompt, however, it's not the typical cmd as it was made to read the DSS filetype and produce a text file with the list from searches like in the commandLine variable
It would be nice to know what I could do to fix the code so that I could input the extra commands. Any help to know how to event check if the commands were being sent or processed by this exe. Eventually, I will be adding many more commands to the exe file to print to the text file, so if there is any way to get python to write to the exe that would help.
#tdelaney, #eryksun Thank you for commenting, your comments about the pipes and delay really helped. I was able to fix the problem by using this code:
##Testing on how to run and use the DSSUTL program
import subprocess
from subprocess import PIPE, STDOUT
import time
DSSUTL = "C:\Users\sduncan\Documents\HEC-DSS\HEC-DSSVue-2_0_1\FromSivaSel\DSSUTL.exe"
mydss = "C:\Users\sduncan\Documents\HEC-DSS\HEC-DSSVue-2_0_1\FromSivaSel\\forecast.dss"
location = "WR.T TO=PythonTextOutput.txt" + " WR.T B=SHAVER RESERVOIR-POOL C=FLOW-IN E=1HOUR F=10203040" + "\n"
filecontent1 = "WR.T B=FLORENCE RESERVOIR-POOL C=FLOW-IN E=1HOUR F=10203040" + "\n"
filecontent2 = "WR.T B=HUNTINGTON LAKE-POOL C=FLOW-IN E=1HOUR F=10203040" + "\n"
filecontentList = [filecontent1, filecontent2]
myList = [DSSUTL, mydss] # commandLine, location
ps = subprocess.Popen(myList , shell=False, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
time.sleep(1)
# input into stdin
ps.stdin.write(location)
time.sleep(1)
ps.stdin.write(filecontent1)
time.sleep(1)
ps.stdin.write(filecontent2)
time.sleep(1)
print ps.communicate()[0]
# End Script
By using the pipes to talk to the program and putting a time delay seemed to fix the problem and allowed me to talk to the console. Even though the console display is blank, by printing the communicate() command, it outputs what the console did and produce the text file with the wanted series.
Thanks for pushing me in the right direction!

Python: Spawn New Minimized Shell

I am attempting to to launch a python script from within another python script, but in a minimized console, then return control to the original shell.
I am able to open the required script in a new shell below, but it's not minimized:
#!/usr/bin/env python
import os
import sys
import subprocess
pyTivoPath="c:\pyTivo\pyTivo.py"
print "Testing: Open New Console"
subprocess.Popen([sys.executable, pyTivoPath], creationflags = subprocess.CREATE_NEW_CONSOLE)
print
raw_input("Press Enter to continue...")
Further, I will need to be able to later remotely KILL this shell from the original script, so I suspect I'll need to be explicit in naming the new process. Correct?
Looking for pointers, please. Thanks!
Note: python27 is mandatory for this application. Eventually will also need to work on Mac and Linux.
Do you need to have the other console open? If you now the commands to be sent, then I'd recommend using Popen.communicate(input="Shell commands") and it will automate the process for you.
So you could write something along the lines of:
# Commands to pass into subprocess (each command is separated by a newline)
commands = (
"command1\n" +
"command2\n"
)
# Your process
py_process = subprocess.Popen(*yourprocess_here*, stdin=PIPE, shell=True)
# Feed process the needed input
py_process.communicate(input=commands)
# Terminate when finished
py_process.terminate()
The code above will execute the process you specify and even send commands but it won't open a new console.

python subprocess.Popen stdin.write

I'm new to python and would like to open a windows cmd prompt, start a process, leave the process running and then issue commands to the same running process.
The commands will change so i cant just include these commands in the cmdline variable below. Also, the process takes 10-15 seconds to start so i dont want to waste time waiting for the process to start and run commands each time. just want to start process once. and run quick commands as needed in the same process
I was hoping to use subprocess.Popen to make this work, though i am open to better methods. Note that my process to run is not cmd, but im just using this as example
import subprocess
cmdline = ['cmd', '/k']
cmd = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
cmd.stdin.write("echo hi") #would like this to be written to the cmd prompt
print cmd.stdout.readline() #would like to see 'hi' readback
cmd.stdin.write("echo hi again") #would like this to be written to the cmd prompt
print cmd.stdout.readline() #would like to see 'hi again' readback
The results arent what i expect. Seems as though the stdin.write commands arent actually getting in and the readline freezes up with nothing to read.
I have tried the popen.communicate() instead of write/readline, but it kills the process. I have tried setting bufsize in the Popen line, but that didn't make too much difference
Your comments suggest that you are confusing command-line arguments with input via stdin. Namely, the fact that system-console.exe program accepts script=filename parameter does not imply that you can send it the same string as a command via stdin e.g., python executable accepts -c "print(1)" command-line arguments but it is a SyntaxError if you pass it as a command to Python shell.
Therefore, the first step is to use the correct syntax. Suppose the system-console.exe accepts a filename by itself:
#!/usr/bin/env python3
import time
from subprocess import Popen, PIPE
with Popen(r'C:\full\path\to\system-console.exe -cli -',
stdin=PIPE, bufsize=1, universal_newlines=True) as shell:
for _ in range(10):
print('capture.tcl', file=shell.stdin, flush=True)
time.sleep(5)
Note: if you've redirected more than one stream e.g., stdin, stdout then you should read/write both streams concurrently (e.g., using multiple threads) otherwise it is very easy to deadlock your program.
Related:
Q: Why not just use a pipe (popen())? -- mandatory reading for Unix environment but it might also be applicable for some programs on Windows
subprocess readline hangs waiting for EOF -- code example on how to pass multiple inputs, read multiple outputs using subprocess, pexpect modules.
The second and the following steps might have to deal with buffering issues on the side of the child process (out of your hands on Windows), whether system-console allows to redirect its stdin/stdout or whether it works with a console directly, and character encoding issues (how various commands in the pipeline encode text).
Here is some code that I tested and is working on Windows 10, Quartus Prime 15.1 and Python 3.5
import subprocess
class altera_system_console:
def __init__(self):
sc_path = r'C:\altera_lite\15.1\quartus\sopc_builder\bin\system-console.exe --cli --disable_readline'
self.console = subprocess.Popen(sc_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
def read_output(self):
rtn = ""
loop = True
i = 0
match = '% '
while loop:
out = self.console.stdout.read1(1)
if bytes(match[i],'utf-8') == out:
i = i+1
if i==len(match):
loop=False
else:
rtn = rtn + out.decode('utf-8')
return rtn
def cmd(self,cmd_string):
self.console.stdin.write(bytes(cmd_string+'\n','utf-8'))
self.console.stdin.flush()
c = altera_system_console()
print(c.read_output())
c.cmd('set jtag_master [lindex [get_service_paths master] 0]')
print(c.read_output())
c.cmd('open_service master $jtag_master')
print(c.read_output())
c.cmd('master_write_8 $jtag_master 0x00 0xFF')
print(c.read_output())
You need to use iter if you want to see the output in real time:
import subprocess
cmdline = ['cmd', '/k']
cmd = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
cmd.stdin.write("echo hi\n")#would like this to be written to the cmd prompt
for line in iter(cmd.stdout.readline,""):
print line
cmd.stdin.write("echo hi again\n")#would like this to be written to the cmd prompt
Not sure exactly what you are trying to do but if you want to input certain data when you get certain output then I would recommend using pexpect

How to execute a command prompt command from python

I tried something like this, but with no effect:
command = "cmd.exe"
proc = subprocess.Popen(command, stdin = subprocess.PIPE, stdout = subprocess.PIPE)
proc.stdin.write("dir c:\\")
how about simply:
import os
os.system('dir c:\\')
You probably want to try something like this:
command = "cmd.exe /C dir C:\\"
I don't think you can pipe into cmd.exe... If you are coming from a unix background, well, cmd.exe has some ugly warts!
EDIT: According to Sven Marnach, you can pipe to cmd.exe. I tried following in a python shell:
>>> import subprocess
>>> proc = subprocess.Popen('cmd.exe', stdin = subprocess.PIPE, stdout = subprocess.PIPE)
>>> stdout, stderr = proc.communicate('dir c:\\')
>>> stdout
'Microsoft Windows [Version 6.1.7600]\r\nCopyright (c) 2009 Microsoft Corporatio
n. All rights reserved.\r\n\r\nC:\\Python25>More? '
As you can see, you still have a bit of work to do (only the first line is returned), but you might be able to get this to work...
Try:
import os
os.popen("Your command here")
Using ' and " at the same time works great for me (Windows 10, python 3)
import os
os.system('"some cmd command here"')
for example to open my web browser I can use this:
os.system(r'"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"')
(Edit)
for an easier way to open your browser I can use this:
import webbrowser
webbrowser.open('website or leave it alone if you only want to open the
browser')
Try adding a call to proc.stdin.flush() after writing to the pipe and see if things start behaving more as you expect. Explicitly flushing the pipe means you don't need to worry about exactly how the buffering is set up.
Also, don't forget to include a "\n" at the end of your command or your child shell will sit there at the prompt waiting for completion of the command entry.
I wrote about using Popen to manipulate an external shell instance in more detail at: Running three commands in the same process with Python
As was the case in that question, this trick can be valuable if you need to maintain shell state across multiple out-of-process invocations on a Windows machine.
Taking some inspiration from Daren Thomas's answer (and edit), try this:
proc = subprocess.Popen('dir C:\\', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
out, err = proc.communicate()
out will now contain the text output.
They key nugget here is that the subprocess module already provides you shell integration with shell=True, so you don't need to call cmd.exe directly.
As a reminder, if you're in Python 3, this is going to be bytes, so you may want to do out.decode() to convert to a string.
Why do you want to call cmd.exe ? cmd.exe is a command line (shell). If you want to change directory, use os.chdir("C:\\"). Try not to call external commands if Python can provide it. In fact, most operating system commands are provide through the os module (and sys). I suggest you take a look at os module documentation to see the various methods available.
It's very simple. You need just two lines of code with just using the built-in function and also it takes the input and runs forever until you stop it. Also that 'cmd' in quotes, leave it and don't change it. Here is the code:
import os
os.system('cmd')
Now just run this code and see the whole windows command prompt in your python project!
Here's a way to just execute a command line command and get its output using the subprocess module:
import subprocess
# You can put the parts of your command in the list below or just use a string directly.
command_to_execute = ["echo", "Test"]
run = subprocess.run(command_to_execute, capture_output=True)
print(run.stdout) # the output "Test"
print(run.stderr) # the error part of the output
Just don't forget the capture_output=True argument and you're fine. Also, you will get the output as a binary string (b"something" in Python), but you can easily convert it using run.stdout.decode().
In Python, you can use CMD commands using these lines :
import os
os.system("YOUR_COMMAND_HERE")
Just replace YOUR_COMMAND_HERE with the command you like.
From Python you can do directly using below code
import subprocess
proc = subprocess.check_output('C:\Windows\System32\cmd.exe /k %windir%\System32\\reg.exe ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 0 /f' ,stderr=subprocess.STDOUT,shell=True)
print(str(proc))
in first parameter just executed User Account setting you may customize with yours.

Categories

Resources