Python - Fork a piped command to background and leave it there - python

I'm new to python, still learning
What i need to do is to fork a complex command to background and continue th execution of my main program, something like this:
I do this from the linux command line (and works ok)
./pgm1 arg1 arg2 arg3 | ./pgm22 arg21 arg22 arg23 arg24 &
so the program goes to background and i can coninue my work.
How can i run the above command in my python program?
Many thanks

You can PIPE the output of the first command to the second using subprocess.Popen:
from subprocess import PIPE,Popen
p = Popen(["./pgm1" ,"arg1" ,"arg2" ,"arg3" ],stdout=PIPE)
p1 = Popen( ["./pgm22", "arg21", "arg22", "arg23" ,"arg24"],stdin=p.stdout,stdout=PIPE)
p.stdout.close()
Popen does not wait for the command to finish.

Related

Python freezes running exe file

I'm doing a simple python gui and on button click it will run a simple command:
os.system("C:/cygwin64/bin/bash.exe")
When I look in the console it ran correctly and but my guy freezes and is not responding.
If I run the the command in the console without python it works perfectly and I start cygwin terminal.
If you know what is cygwin is there a better way to start it in the same terminal?
os.system blocks the current thread, you can use os.popen in order to do that in another thread, and it also gives you few methods to detach/read/write etc' that process.
for example,
import os
a = os.popen("python -c 'while True: print(1)'")
will create a new process that will be terminated as soon as you terminate your script.
you can do
for i in a:
print(i)
for example, and it will block the thread as os.system does.
you can a.detach() it whenever you want to terminate the process.
However, os.system
import os
os.system("python -c 'while True: print(1)'")
it will output the 1s forever until you terminate the script.
You can use function Popen in package subprocess. It has many possible arguments that allow you to pipe input to and/or pipe output from the program you are running. But if you just want to execute bash.exe while allowing your original Python program to continue running and eventually wait for the completion of bash.exe, then:
import subprocess
# pass a list of command-line arguments:
p = subprocess.Popen(["C:/cygwin64/bin/bash.exe"])
... # continue executing
# wait for the subprocess (bash.exe) to end:
exit_code = p.wait()

How to run python subprocess with real-time output?

When I run a shell command in Python it does not show the output until the command is finished. the script that I run takes a few hours to finish and I'd like to see the progress while it is running.
How can I have python run it and show the outputs in real-time?
Use the following function to run your code. In this example, I want to run an R script with two arguments. You can replace cmd with any other shell command.
from subprocess import Popen, PIPE
def run(command):
process = Popen(command, stdout=PIPE, shell=True)
while True:
line = process.stdout.readline().rstrip()
if not line:
break
print(line)
cmd = f"Rscript {script_path} {arg1} {arg2}"
run(cmd)

Restart ruby script after crashing (python)

I am new to Python. I want to make it show Ruby puts and also to make my ruby script start all over when it crashes:
import subprocess
cmd = "ruby script.rb"
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
output, errors = p.communicate()
Any help?
I don't think Python is a good solution for this problem. It's much better to write a simple CMD (if you're using Windows) or Bash (if you're using Unix-like OS) script:
#!/bin/bash
trap handler SIGINT
RUN=true
handler() {
RUN=false
}
while [ ${RUN} = true ]; do
python child.py
done
It gives you realtime output, which is much harder to achieve in Python. And automatically restarts script, when it exits.

Run a perl script from my python script, print the output and wait for it to finish

I have a python script which at one point is required to run a perl script, wait for it to finish, then continue.
As this case will only occur on a windows machine, I thought I could simply open a new cmd and run the perl script there, but I'm having difficulties doing so.
import os
os.system("start /wait cmd /c {timeout 10}")
should open a new cmd and sleep for 10 seconds, but it closes right away. I don't want to put the perl script in position of the timeout 10, as it is quite resource intensive.
Another idea was to use a subprocess with call or Popen and wait.
perl_script = subprocess.call(['script.pl', params])
But I'm not sure what would happen to the stdout of the perl script in such a case.
I know the location and the parameters of the perl script.
How can I run a perl script from my python script, print the output (a lot) and wait for it to finish?
edit:
As suggested by #rchang, I added the subprocess with communicate as following and it works just as intended.
import subprocess, sys
perl = "C:\\perl\\bin\\perl.exe"
perl_script "C:\\scripts\\perl\\flamethrower.pl"
params = " --mount-doom-hot"
pl_script = subprocess.Popen([perl, perl_script, params], stdout=sys.stdout)
pl_script.communicate()
These are my first lines of perl, just a quick copy/past script to test this.
print "Hello Perld!\n";
sleep 10;
print "Bye Perld!\n";
import subprocess
import sys
perl_script = subprocess.Popen(["script.pl", params], stdout=sys.stdout)
perl_script.communicate()
This should hook up the stdout of the subprocess to the stdout stream of the Python script, provided you won't actually need the Python script to output anything else meaningful during execution that may not be related to the subprocess output.
You could try:
perl_script = subprocess.check_output(["script.pl", params])
print perl_script

How to execute a shell script in the background from a Python script

I am working on executing the shell script from Python and so far it is working fine. But I am stuck on one thing.
In my Unix machine I am executing one command in the background by using & like this. This command will start my app server -
david#machineA:/opt/kml$ /opt/kml/bin/kml_http --config=/opt/kml/config/httpd.conf.dev &
Now I need to execute the same thing from my Python script but as soon as it execute my command it never goes to else block and never prints out execute_steps::Successful, it just hangs over there.
proc = subprocess.Popen("/opt/kml/bin/kml_http --config=/opt/kml/config/httpd.conf.dev &", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, executable='/bin/bash')
if proc.returncode != 0:
logger.error("execute_steps::Errors while executing the shell script: %s" % stderr)
sleep(0.05) # delay for 50 ms
else:
logger.info("execute_steps::Successful: %s" % stdout)
Anything wrong I am doing here? I want to print out execute_steps::Successful after executing the shell script in the background.
All other command works fine but only the command which I am trying to run in background doesn't work fine.
There's a couple things going on here.
First, you're launching a shell in the background, and then telling that shell to run the program in the background. I don't know why you think you need both, but let's ignore that for now. In fact, by adding executable='/bin/bash' on top of shell=True, you're actually trying to run a shell to run a shell to run the program in the background, although that doesn't actually quite work.*
Second, you're using PIPE for the process's output and error, but then not reading them. This can cause the child to deadlock. If you don't want the output, use DEVNULL, not PIPE. If you want the output to process yourself, use proc.communicate().**, or use a higher-level function like check_output. If you just want it to intermingle with your own output, just leave those arguments off.
* If you're using the shell because kml_http is a non-executable script that has to be run by /bin/bash, then don't use shell=True for that, or executable, just make make /bin/bash the first argument in the command line, and /opt/kml/bin/kml_http the second. But this doesn't seem likely; why would you install something non-executable into a bin directory?
** Or you can read it explicitly from proc.stdout and proc.stderr, but that gets more complicated.
At any rate, the whole point of executing something in the background is that it keeps running in the background, and your script keeps running in the foreground. So, you're checking its returncode before it's finished, and then moving on to whatever's next in your code, and never coming back again.
It seems like you want to wait for it to be finished. In that case, don't run it in the background—use proc.wait, or just use subprocess.call() instead of creating a Popen object. And don't use & either, of course. While we're at it, don't use the shell, either:
retcode = subprocess.call(["/opt/kml/bin/kml_http",
"--config=/opt/kml/config/httpd.conf.dev"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if retcode != 0:
# etc.
Now, you won't get to that if statement until kml_http finishes running.
If you want to wait for it to be finished, but at the same time keep doing other stuff, then you're trying to do two things at once in your program, which means you need a thread to do the waiting:
def run_kml_http():
retcode = subprocess.call(["/opt/kml/bin/kml_http",
"--config=/opt/kml/config/httpd.conf.dev"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if retcode != 0:
# etc.
t = threading.Thread(target=run_kml_http)
t.start()
# Now you can do other stuff in the main thread, and the background thread will
# wait around until kml_http is finished and execute the `if` statement whenever
# that happens
You're using stderr=PIPE, stdout=PIPE which means that rather than letting the stdin and stdout of the child process be forwarded to the current process' standard output and error streams, they are being redirected to a pipe which you must read from in your python process (via proc.stdout and proc.stderr.
To "background" a process, simply omit the usage of PIPE:
#!/usr/bin/python
from subprocess import Popen
from time import sleep
proc = Popen(
['/bin/bash', '-c', 'for i in {0..10}; do echo "BASH: $i"; sleep 1; done'])
for x in range(10):
print "PYTHON: {0}".format(x)
sleep(1)
proc.wait()
which will show the process being "backgrounded".

Categories