To launch a program in a non blocking way but still being able to see the output of program, the program has to be launched in a separate thread or process. Ryan has posted a nice code sample here: Python Subprocess.Popen from a thread
Keep in mind that the last line print myclass.stdout will print the output how it appears at that time. If program is just being launched, it might not have output anything at all, so your code should probably read from myclass.stdout until it receives the line you need.
I am wondering if this can be achieved with subprocess. Run the process and write output
I have two files:
main.py:
import subprocess
import shlex
def main():
command = 'python test_output.py'
logfile = open('output', 'w')
proc = subprocess.Popen(shlex.split(command), stdout=logfile)
if __name__ == "__main__":
main()and test_output.py:
from time import sleep
import os
for i in range(0, 30):
print("Slept for => ", i+1, "s")
sleep(1)
os.system("notify-send completed -t 1500")The output of the process is written to logfile once the child process is completed. Is there any way to:
Start child process from main and exit it (like it does now).
Keep running the child process in background.
As child process produces an output, write it immediately to logfile. (Don't wait for the child process to finish, as it does now.)
Or write to Named Pipes alternatively but don't keep it waiting to read (non-blocking)
Is it possible to do everything in background, without keeping main.py waiting?
How to run Python's subprocess and leave it in background - Stack Overflow
Start a background process in Python - Stack Overflow
python - Execute Subprocess in Background - Stack Overflow
Explicit support for backgrounded subprocesses
Videos
To launch a program in a non blocking way but still being able to see the output of program, the program has to be launched in a separate thread or process. Ryan has posted a nice code sample here: Python Subprocess.Popen from a thread
Keep in mind that the last line print myclass.stdout will print the output how it appears at that time. If program is just being launched, it might not have output anything at all, so your code should probably read from myclass.stdout until it receives the line you need.
You can run it in a thread (so that it doesn't block your code from running), and get the output until you get the second line, then wait for it to terminate. This is an example that will read the output from the command dir /s on Windows to get all the directory listing.
import subprocess, thread, time
def run():
global can_break
args = ["dir", "/s"]
shell = True
count = 0
popen = subprocess.Popen(args, shell=shell, stdout=subprocess.PIPE)
while True:
line = popen.stdout.readline()
if line == "": continue
count += 1
if count == 2:
do_something_with(line)
break
print "We got our line, we are waiting now"
popen.wait()
print "Done."
can_break = True
def do_something_with(line):
print '>>> This is it:', line
thread.start_new_thread(run, tuple())
can_break = False
while not can_break:
print 'Wait'
time.sleep(1)
print 'Okay!'
Output will look like:
Wait >>> This is it: Volume Serial Number is XXXX-XXXX We got our line, we are waiting now Wait Wait Wait . . . Done. Wait Okay!
From the Popen.communicate documentation (emphasis mine):
Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child.
If you don't want to wait for the process to terminate, then simply don't call communicate:
subprocess.Popen(full_command, close_fds=True)
Might be another way of doing it, with the optional capability to inspect the subprocess output for a while, from github.com/hologram-io/hologram-python pppd.py file:
self.proc = Popen(self._commands, stdout=PIPE, stderr=STDOUT)
# set stdout to non-blocking
fd = self.proc.stdout.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
While jkp's solution works, the newer way of doing things (and the way the documentation recommends) is to use the subprocess module. For simple commands its equivalent, but it offers more options if you want to do something complicated.
Example for your case:
import subprocess
subprocess.Popen(["rm","-r","some.file"])
This will run rm -r some.file in the background. Note that calling .communicate() on the object returned from Popen will block until it completes, so don't do that if you want it to run in the background:
import subprocess
ls_output=subprocess.Popen(["sleep", "30"])
ls_output.communicate() # Will block for 30 seconds
See the documentation here.
Also, a point of clarification: "Background" as you use it here is purely a shell concept; technically, what you mean is that you want to spawn a process without blocking while you wait for it to complete. However, I've used "background" here to refer to shell-background-like behavior.
Note: This answer is less current than it was when posted in 2009. Using the subprocess module shown in other answers is now recommended in the docs
(Note that the subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using these functions.)
If you want your process to start in the background you can either use system() and call it in the same way your shell script did, or you can spawn it:
import os
os.spawnl(os.P_DETACH, 'some_long_running_command')
(or, alternatively, you may try the less portable os.P_NOWAIT flag).
See the documentation here.
& is a shell feature. If you want it to work with subprocess, you must specify shell=True like:
subprocess.call(command, shell=True)
This will allow you to run command in background.
Notes:
Since
shell=True, the above usescommand, notcommand_list.Using
shell=Trueenables all of the shell's features. Don't do this unlesscommandincludingthingycomes from sources that you trust.
Safer Alternative
This alternative still lets you run the command in background but is safe because it uses the default shell=False:
p = subprocess.Popen(command_list)
After this statement is executed, the command will run in background. If you want to be sure that it has completed, run p.wait().
If you want to execute it in Background I recommend you to use nohup output that would normally go to the terminal goes to a file called nohup.out
import subprocess
subprocess.Popen("nohup usr/local/bin/otherscript.pl {0} >/dev/null 2>&1 &", shell=True)
>/dev/null 2>&1 & will not create output and will redirect to background
Hello,
Level: Beginner
The code below has a loop that listens out for keypresses from an attached 3x4 keypad. If certain keys are pressed it plays a sound from a local file using aplay, an audio stream from an URL using mplayer, or shutdowns the machine
When playing the .wav in aplay, once the sound is played the loop continues and restarts, monitoring for other keypad presses. This is fine. However when key 3 or 4 are pressed and the radio streams begin to play, they never end so, the loop never continues.
I would like to be able to switch between radio stations essentially. How can I achieve this in the most proper way? It goes without saying I only want one instance of mplayer to be playing one radio station at a time.
All help is appreciated.
import time
import digitalio
import board
import adafruit_matrixkeypad
import os
import subprocess
# rows and columns are mixed up for https://www.adafruit.com/product/3845
cols = [digitalio.DigitalInOut(x) for x in (board.D27,board.D4,board.D10)]
rows = [digitalio.DigitalInOut(x) for x in (board.D17,board.D11,board.D9,board.D22)]
keys = ((1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12))
keypad = adafruit_matrixkeypad.Matrix_Keypad(rows, cols, keys)
print("Program is Running") #This is confirm that the program is running and ready for input
subprocess.run(['aplay', '/home/pi/Sounds/Ding.wav']) #This is confirm that the program is running and ready for input
while True:
keys = keypad.pressed_keys
if keys == [1]:
subprocess.run(['aplay', '/home/pi/Sounds/Clapping.wav'])
if keys == [2]:
subprocess.run(['aplay', '/home/pi/Sounds/Cheering.wav'])
if keys == [3]:
subprocess.run(['mplayer', 'http://playerservices.streamtheworld.com/pls/WDUZFM.pls'])
if keys == [4]:
subprocess.run(['mplayer', 'https://live.wostreaming.net/direct/goodkarma-wktifmmp3-ibc2'])
if keys == [10, 11, 12]:
os.system("sudo shutdown -h now")
time.sleep(1.5)Use subprocess.Popen to run perf. Then, use pipe.communicate() to send input and get the process's output.
After you've done, call pipe.terminate() to terminate the process.
For example:
pipe = subprocess.Popen(["perf","stat","-p",str(GetMyProcessID())], stdout=PIPE)
pipe.terminate()
stdout, stderr = pipe.communicate()
print stdout
First: I advise against calling perf from within your python process (as you see in the complexity of the task below), but instead use is from the command line:
sudo perf stat -- python test.py
If you really want to call perf from within python then you'll face some tricky problems:
- to terminate
perfand make it output the gathered performance stats you need to send it theSIGINTsignal (try it out withsudo perf stat -p mypid:ctrl-\will print nothing whereasctrl-cwill) - you need to capture
stderras perf sends its output tostderr(at least in my version) - you need to use
fork()with one process sendingSIGINTand the other reading it's output while the process dies. Without forks it won't work because after youSIGINTed theperfprocess you cannot read from stdin any more as the process is already gone, and when you read fromstdinfirst you won't get any output until perf is correctly terminated.
That means you'd end up with this python program:
import subprocess
import os
import signal
import time
perf = subprocess.Popen(['perf', 'stat', '-p', str(os.getpid())], stderr=subprocess.PIPE)
# <-- your code goes here
if os.fork() == 0:
# child
time.sleep(1) # wait until parent runs `stderr.read()`
perf.send_signal(signal.SIGINT)
exit(0)
# parent
print("got perf stats>>{}<<".format(perf.stderr.read().decode("utf-8")))
The time.sleep(1) bit is ugly, what it does it that it will but I guess it will do the trick for 99% of the cases. It has almost no influence on the perf data, the only influence it has is on the "total runtime" (*xx seconds time elapsed)