I am stuck in a while True loop which I can't seem to break, any suggestions please:
command1 = transporterLink + " -m verify -f " + indir1 + " -u " + username + " -p " + password + " -o " + indir1 + "/VerifyLog.txt -s " + provider1 + " -v eXtreme"
master, slave = pty.openpty()
process = Popen(command1, shell=True, stdin=PIPE, stdout=slave, stderr=slave, close_fds=True)
stdout = os.fdopen(master)
while True:
wx.Yield()
line = stdout.readline()
print line.rstrip()
if not line:
break
process.wait()
The simplest explanation is that you never get an empty line from stdout. Note that print line.rstrip() does not modify line; for example, if the last line ended with a newline, the loop would continue.
Sorted. I know that at the end of the last line it will return one of two strings so just needed to search for either of these two:
process = Popen(command1, shell=True, stdin=PIPE, stdout=slave, stderr=slave, close_fds=True)
stdout = os.fdopen(master)
while True:
wx.Yield()
line = stdout.readline()
line = line.rstrip()
print line
if "Returning 1" in line:
break
if "Returning 0" in line:
break
Related
I'm trying to make python script (currently on windows) which will open some sub-processes (which will run infinitely) and script should periodically check do all of opened sub-processes still work correctly. So it should be done with while loop, I guess.
The sub-processes are about FFMPEG livestreaming.
The problem is when I do time.sleep(n) in my loop, because then every FFMPEG livestream stops, so I suppose time.sleep affect on all of child subprocesses.
I have no idea how to make it work.
Here is my python code:
import os, time, sys, datetime, smtplib, configparser, logging, subprocess, psutil
import subprocess
def forwardudpstream(channel_number, ip_input, ip_output):
try:
ffmpeg_command = 'ffmpeg -i udp://' + ip_input + ' -vcodec copy -acodec copy -f mpegts "udp://' + ip_output + '?pkt_size=1316"'
ffmpeg_output = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False)
return str(ffmpeg_output.pid)
except:
print ("Exception!")
return '0'
while True:
configuration = 'config.ini'
channel_list_file = 'CHANNEL_LIST.conf'
pid_folder = "D:\\Forward_UDP_Stream\\pids\\"
channel_list = [line.rstrip('\n') for line in open(channel_list_file)]
for line in channel_list:
if not line.startswith('#') and ('|' in line):
channel_number, ip_input, ip_output = line.split('|')
print('----------')
print("Channel number = ", channel_number)
print("IP Input = ", ip_input)
print("IP Output = ", ip_output)
pid_file_found = False
print("Checking if pid file exists...")
for pidfile in os.listdir(pid_folder):
if pidfile.startswith(channel_number + '-'):
print("Pid file is found for this channel.")
pid_file_found = True
pid = int(pidfile.split('-')[1].split('.')[0])
print("PID = ", str(pid))
print("Checking if corresponding process is active...")
if not psutil.pid_exists(pid):
print("Process is not active.")
print("Removing old pid file.")
os.remove(pid_folder + pidfile)
print("Starting a new process...")
pid_filename = channel_number + '-' + forwardudpstream(channel_number, ip_input, ip_output) + '.pid'
pid_file = open(pid_folder + pid_filename, "a")
pid_file.write("Process is running.")
pid_file.close()
else:
print("Process is active!")
break
if pid_file_found == False:
print("Pid file is not found. Starting a new process and creating pid file...")
pid_filename = channel_number + '-' + forwardudpstream(channel_number, ip_input, ip_output) + '.pid'
pid_file = open(pid_folder + pid_filename, "a")
pid_file.write("Process is running.")
pid_file.close()
time.sleep(10)
Here is my CHANNEL_LIST.conf file example:
1|239.1.1.1:10000|239.1.1.2:10000
2|239.1.1.3:10000|239.1.1.4:10000
Perhaps there is some other solution to put waiting and sub-processes to work together. Does anyone have an idea?
UPDATE:
I finally make it work when I removed stdout=subprocess.PIPE part from the subprocess command.
Now it looks like this:
ffmpeg_output = subprocess.Popen(ffmpeg_command, stderr=subprocess.STDOUT, shell=False)
So now I'm confused why previous command was making a problem...?
Any explanation?
this is the function i am creating, i have one argument that can tell to print real time or not since some of the process take like an hour. and since i am subprocesing several at the same time, another argument to raise an error and stop everything, or just let the main script run.
but if i do print_real_time True, i loose the p.communicate()
i could store all the prints from the iter in a variable and return that, but how do i put in order the std out, and the stderr, and get the return value to see if did fail or not?
def launch_subprocess_cmd(command_to_lunch, cwd=None, print_real_time=False, raise_errors=True):
"""
for a given command line will lunch that as a subprocess
:param command_to_lunch: string
:param print_real_time: boolean
:param cwd: the folder path from where the command should be run.
:param raise_errors: boolean if the return code of the subprocess is different than 0 raise an error an stop all scripts.
else the main script will keep running and can access the third return value of this function and decide what to do with it.
:return: list com return the stdout and the stderr of the Popen subprocess.
"""
if cwd is None:
p = subprocess.Popen(command_to_lunch, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
else:
p = subprocess.Popen(command_to_lunch, cwd=cwd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
if print_real_time is True:
for i in iter(p.stdout.readline, b''):
print i
com = p.communicate()
if raise_errors is True:
if p.returncode != 0:
raise ValueError("\n\nSubprocess fail: \n" + "Error captures: \n" + "stdout:\n" + com[0] + "\nstderr:\n" + com[1] + "\n")
# com[0] is std_out, com[1] is std_err and p.return code is if the subprocess was successful or not with a int number
return com[0], com[1], p.returncode
thanks guys =)
A possible solution to your problem is to store the stdout stream in a list when print_real_time is True and then use the content of the list to generate the stdout data string. If print_real_time is not True, then use the content from com[0] instead.
def launch_subprocess_cmd(cmd, cwd=None, print_real_time=False, raise_errors=True):
"""
for a given command line will lunch that as a subprocess
:param cmd: string
:param print_real_time: boolean
:param cwd: the folder path from where the command should be run.
:param raise_errors: boolean if the return code of the subprocess is different
than 0 raise an error an stop all scripts else
the main script will keep running and can access the third
return value of this function and decide what to do with it.
:return: list com return the stdout and the stderr of the Popen subprocess.
"""
if cwd is None:
p = subprocess.Popen(cmd, stderr=subprocess.PIPE,
stdout=subprocess.PIPE, shell=True)
else:
p = subprocess.Popen(cmd, cwd=cwd, stderr=subprocess.PIPE,
stdout=subprocess.PIPE, shell=True)
stdout_list = []
if print_real_time is True:
for i in iter(p.stdout.readline, b''):
stdout_list.append(i)
print i
com = p.communicate()
stdout_data = "".join(stdout_list) if print_real_time is True else com[0]
if raise_errors is True:
if p.returncode != 0:
raise ValueError("\n\nSubprocess fail: \n" + "Error captures: \n" +
"stdout:\n" + stdout_data + "\nstderr:\n" +
com[1] + "\n")
# stdout_data is stdout, com[1] is stderr and
# p.return code is if the subprocess was successful or not with a int number
return stdout_data, com[1], p.returncode
As a side note, I would also urge you to try to rewrite the program to not use shell=True in your Popen calls. It may require that you preprocess the input cmd into a list of base command and arguments, but it is generally considered a bad idea to use shell=True.
launch_subprocess_cmd(command_to_lunch, cwd=None, print_real_time=False, raise_errors=True):
if cwd is None:
p = subprocess.Popen(command_to_lunch, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
else:
p = subprocess.Popen(command_to_lunch, cwd=cwd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
stdout_list = []
errout_list = []
if print_real_time is True:
for i in iter(p.stdout.readline, b''):
stdout_list.append(i)
print i
for j in iter(p.stderr.readline, b''):
errout_list.append(j)
print j
com = p.communicate()
if print_real_time is True:
stdout_data = "".join(stdout_list)
std_err_data = "".join(errout_list)
else:
stdout_data = com[0]
std_err_data = com[1]
if raise_errors is True:
if p.returncode != 0:
raise ValueError("\n\npopen fail:\n" + command_to_lunch + "\nError:\n" + "Error captures:\n" + "stdout:\n" + stdout_data + "\nstderr:\n" + std_err_data + "\n")
# com[0] is out, com[1] is errors and p.return code is if it fail or not
return stdout_data, std_err_data, p.returncode
I am running the below code which runs a command line application which runs for about 40 mins. While this is running my QUIT button is not accessible so I am unable to quit the running application. The below code and the button are both seated in their own def. Any ideas as to how I can get a working quit button while my application is running?
command1 = transporterLink + " -m verify -f " + indir1 + " -u " + username + " -p " + password + " -o " + logPath + " -s " + provider1 + " -v eXtreme"
master, slave = pty.openpty()
process = Popen(command1, shell=True, stdin=PIPE, stdout=slave, stderr=slave, close_fds=True)
stdout = os.fdopen(master)
global subject
subject = "Test"
while True:
wx.Yield()
line = stdout.readline()
line = line.rstrip()
print line
if "Returning 1" in line:
result1 = "Verify FAILED!"
subject = "FAILED! - "
self.sendEmail(self)
break
if "Returning 0" in line:
result1 = "Verify PASSED!"
subject = "PASSED! - "
self.sendEmail(self)
break
stdout.readline is blocking until there is something in stdout. You could use select module's poll
command1 = transporterLink + " -m verify -f " + indir1 + " -u " + username + " -p " + password + " -o " + logPath + " -s " + provider1 + " -v eXtreme"
master, slave = pty.openpty()
process = Popen(command1, shell=True, stdin=PIPE, stdout=master, stderr=slave, close_fds=True)
stdout = os.fdopen(master)
import select
q = select.poll()
q.register(stdout,select.POLLIN)
global subject
subject = "Test"
while True:
wx.Yield()
events = q.poll(0)
for fd, flags in events:
assert(fd == stdout.fileno())
line = stdout.readline()
print line
if "Returning 1" in line:
result1 = "Verify FAILED!"
subject = "FAILED! - "
self.sendEmail(self)
sys.exit(0)
if "Returning 0" in line:
result1 = "Verify PASSED!"
subject = "PASSED! - "
self.sendEmail(self)
sys.exit(0)
I have the below command in my python script running a command line application which is currently running 'blind' in the background. If I run this command from a command line, mac or PC, I get a real-time readout of that application running, as it runs for 40 mins+ and reports various different info while it is running. Currently as I say it runs blind and gives me all the info at the end on a readout in python, but I want it to essentially open a command line and run so I can see all the info in real-time, but i can't find a way to do this. Here is my current code using a subprocess.Popen. Any other ways?
command1 = transporterLink + " -m verify -f " + indir1 + " -u " + username + " -p " + password + " -o " + indir1 + "\\VerifyLog.txt -s " + provider1 + " -v eXtreme"
process = subprocess.Popen(command1, stdout=subprocess.PIPE, shell=True)
I wrote about this a few years ago, but I don't think I titled the article very well:
http://www.blog.pythonlibrary.org/2010/06/05/python-running-ping-traceroute-and-more/
Basically you need to redirect stdout. I usually do something like this:
class RedirectText:
def __init__(self,aWxTextCtrl):
self.out=aWxTextCtrl
def write(self,string):
self.out.WriteText(string)
And then in my actual wx class, I do something like this in the init:
self.redir=RedirectText(log)
sys.stdout=self.redir
Then when you call subprocess, you would do something like this example:
def pingIP(self, ip):
proc = subprocess.Popen("ping %s" % ip, shell=True,
stdout=subprocess.PIPE)
print
while True:
line = proc.stdout.readline()
wx.Yield()
if line.strip() == "":
pass
else:
print line.strip()
if not line: break
proc.wait()
Note the wx.Yield() call. That allows wxPython to update when we print the line to stdout, which we have redirected to a text control.
Here is an example of sorts:
import subprocess
import sys
import wx
class RedirectText:
def __init__(self,aWxTextCtrl):
self.out=aWxTextCtrl
def write(self,string):
self.out.WriteText(string)
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Test")
panel = wx.Panel(self)
log = wx.TextCtrl(panel, wx.ID_ANY, size=(300,100),
style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
btn = wx.Button(panel, label="Run")
btn.Bind(wx.EVT_BUTTON, self.onRun)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(log, 1, wx.ALL|wx.EXPAND, 5)
sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
panel.SetSizer(sizer)
self.redir=RedirectText(log)
sys.stdout=self.redir
#----------------------------------------------------------------------
def onRun(self, event):
""""""
command1 = transporterLink + " -m verify -f " + indir1 + " -u " + username + " -p " + password + " -o " + indir1 + "\\VerifyLog.txt -s " + provider1 + " -v eXtreme"
process = subprocess.Popen(command1, stdout=subprocess.PIPE, shell=True)
while True:
line = process.stdout.readline()
wx.Yield()
print line
if not line:
break
process.wait()
#----------------------------------------------------------------------
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame()
frame.Show()
app.MainLoop()
I go it to work by changing this section from Mikes answer, but only trouble is now when the application ends and the output finishes printing lines my python freezes. Any ideas why?
def onRun(self, event):
""""""
command1 = transporterLink + " -m verify -f " + indir1 + " -u " + username + " -p " + password + " -o " + indir1 + "\\VerifyLog.txt -s "
+ provider1 + " -v eXtreme"
master, slave = pty.openpty()
process = Popen(command1, shell=True, stdin=PIPE, stdout=slave, stderr=slave, close_fds=True)
stdout = os.fdopen(master)
while True:
line = stdout.readline()
wx.Yield()
print line.rstrip()
if not line:
break
process.wait()
I have an app I've scraped together to try and spawn 3 threads and ssh into a server simultaneously.
I wrote an obviously offensively coded application which I know is wrong which I am looking for some guidance for, to accomplish my initial end goal as mentioned above.
For the argument passing, I know I need to finesse it with something like cmd or cmd2 later on but for now that's not my primary concern.
I know that right now I'm spawning a subprocess and doing things serially. I look forward to your replies.
#!/usr/bin/python
import sys, os
import subprocess
if (len(sys.argv) > 1):
if( sys.argv[1] == 'start' ):
print "starting jboss"
arg = str(sys.argv[1])
elif( sys.argv[1] == 'stop' ):
print "stopping"
elif( sys.argv[1] == 'status' ):
print "getting status"
arg = str(sys.argv[1])
print arg
else:
print "start or stop?"
exit(1)
else:
print "unexpected error"
host = "10.24.14.10 "
command = "sudo /etc/init.d/jbossas " + arg
fullcommand = "ssh " + " " + host + " " + " " + command + " "+ arg
print "full command: ", fullcommand
process = subprocess.Popen(fullcommand, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output,stderr = process.communicate()
status = process.poll()
print output
host = "10.24.14.20 "
fullcommand = "ssh " + " " + host + " " + " " + command + " "+ arg
process = subprocess.Popen(fullcommand, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output,stderr = process.communicate()
status = process.poll()
print output
host = "10.30.1.1 "
fullcommand = "ssh " + " " + host + " " + " " + command + " "+ arg
process = subprocess.Popen(fullcommand, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output,stderr = process.communicate()
status = process.poll()
print output