os.system doesn't work until getting input in python - python

I am trying to run a youtube-dl command but when os.system(command) run, it is waiting an input on terminal(there is no input required). I press enter 2-3 time than it starts downloading.
url = sys.argv[1]
command = "youtube-dl " + url
print("downloading...")
os.system(command)
print("test")
I can't see "test" output. command works on cmd properly. waiting or subprocess command not working.

Using subprocess instead of os.system will let you set stdin=subprocess.DEVNULL so it can't read from stdin (without going to the TTY, which most programs don't). Also, passing a list and keeping the default shell=False avoids security issues where contents inside the URL could be treated by the shell as commands to run.
subprocess.run(["youtube-dl", url], stdin=subprocess.DEVNULL)

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)

Start command prompt application/script from within Python, capture output and send input

I've been trying to run some applications with arguments in windows command prompt, but within a Python script. I am encountering issues in understanding the subprocess module and how I could use it to send inputs, capture outputs and use the data in future functions or loops.
Let's take, for example, Windows Management Instrumentation Command-Line:
I would like to launch a command prompt from a Python script, start wmic, do some stuff then exit back to command prompt.
I know how to strat the cmd and even wmic:
import subprocess
cmd = subprocess.Popen(["cmd", "/K", "wmic"])
What I don't know is how to send commands to wmic. I have tried the following:
import subprocess
cmd = subprocess.Popen(["cmd", "/K", "wmic"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdoutdata, stderrdata = cmd.communicate(input="product get name")
or
cmd.stdin.write("product get name")
cmd.stdin.flush()
Doesn't work. What I would've wanted in this example, is to start Command Prompt, start WMIC, send a command (product/process get name), capture the output of WMIC and use it to do something:
for line in cmd.stdout:
if line == "some string":
do this or do that
In the same time, I would like the output to be printed in the opened command prompt.
I would appreciate any help.

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!

automation of processes by python

I'm trying to write a python script that start a process and do some operations atferward.
The commands that I want to automate by script are circled as red in the picture.
The problem is that after performing first command, qemu environment will be run and the other commands should be executed on the qemu environment. So I want to know how can I do these commands by an script in python? Because as I know I can do the first command but I do not know how can I do those commands when I am going to qemu environment.
Could you help me how can I do this process?
First thing that came to mind was pexpect, a quick search on google turned up this blog post automatically-testing-vms-using-pexpect-and-qemu which seems to be pretty much along the lines of what you are doing:
import pexpect
image = "fedora-20.img"
user = "root"
password = "changeme"
# Define the qemu cmd to run
# The important bit is to redirect the serial to stdio
cmd = "qemu-kvm"
cmd += " -m 1024 -serial stdio -net user -net nic"
cmd += " -snapshot -hda %s" % image
cmd += " -watchdog-action poweroff"
# Spawn the qemu process and log to stdout
child = pexpect.spawn(cmd)
child.logfile = sys.stdout
# Now wait for the login
child.expect('(?i)login:')
# And login with the credentials from above
child.sendline(user)
child.expect('(?i)password:')
child.sendline(password)
child.expect('# ')
# Now shutdown the machine and end the process
if child.isalive():
child.sendline('init 0')
child.close()
if child.isalive():
print('Child did not exit gracefully.')
else:
print('Child exited gracefully.')
You could do it with subprocess.Popen also, checking the stdout for the (qemu) lines and writing to stdin. Something roughly like this:
from subprocess import Popen,PIPE
# pass initial command as list of individual args
p = Popen(["./tracecap/temu","-monitor",.....],stdout=PIPE, stdin=PIPE)
# store all the next arguments to pass
args = iter([arg1,arg2,arg3])
# iterate over stdout so we can check where we are
for line in iter(p.stdout.readline,""):
# if (qemu) is at the prompt, enter a command
if line.startswith("(qemu)"):
arg = next(args,"")
# if we have used all args break
if not arg:
break
# else we write the arg with a newline
p.stdin.write(arg+"\n")
print(line)# just use to see the output
Where args contains all the next commands.
Don't forget that Python has batteries included. Take a look of the Suprocess module in the standard lib. There a lot of pitfalls managing processes, and the module take care of them all.
You probably want to start a qemu process and send the next commands writing to its standard input (stdin). Subprocess module will allow you to do it. See that qemu has command line options to connect to stdi: -chardev stdio ,id=id

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

Categories

Resources