I'm trying to write a script that calls a python program, pauses until the program outputs a certain message (not when the program ends), then moves on.
If I have example.py like this that just runs indefinitely:
doSomething()
print('I did something')
doSomethingElseForever()
I want to have a script something like this:
echo "Running python program"
python3 example.py &
waitForOutput("I did something")
echo "Python program did something, it's still running in the background"
doSomeMoreScriptStuff
Ideally, I would just run the script and it would launch example.py, pause until example.py output "I did something", then continue on to launch more programs or whatever, without stopping example.py (hence the &).
I'm working in Ubuntu BTW.
Edit: I think in my particular application at the moment I could just change my python script to create a file instead of print(), but for the sake of learning (and because that seems like a convoluted way to do things), let's assume I can't edit the python file. So all I have to work with is the known output of a print() statement.
CodePudding user response:
You can do this with pexpect
. I start a thread which calls pexpect.spawn()
to run your child script. It waits for the output you want and then sets an event so the main program knows the event has occurrred. It then waits for the child to exit, which, in turn, allows the main program to exit:
#!/usr/bin/env python3
import pexpect
import time
import threading
doneIt = threading.Event()
def childHandler():
"""Spawns the child and manages its output"""
global doneIt
print('HANDLER: Spawning child')
child = pexpect.spawn('./example.sh')
print('HANDLER: Child spawned, waiting for it to do something')
child.expect('I did something')
doneIt.set()
print('HANDLER: Waiting for child to finish')
child.expect(pexpect.EOF)
print('HANDLER: Done')
if __name__ == "__main__":
print('MAIN: Starting')
cH = threading.Thread(target=childHandler)
cH.start()
# Wait for event and do other stuff, like printing
while True:
print('MAIN: waiting for child to do something')
if doneIt.wait(1):
break
print('MAIN: Continuing...')
# Wait till childHandler exits before exiting
cH.join()
print('MAIN: Exit')
I used this example.sh
as a mock-up of the Python script you call:
#!/bin/bash
LOG="run.txt"
date 'Running: %H:%M:%S' > "$LOG"
for ((i=8;i>0;i--)) ; do
date 'Running: %H:%M:%S' >> "$LOG"
sleep 1
done
date 'SUCCESS: %H:%M:%S' >> "$LOG"
echo "I did something"
for ((i=1;i<10;i )) ; do
date 'Continuing: %H:%M:%S' >> "$LOG"
sleep 1
done
date 'DONE: %H:%M:%S' >> "$LOG"
And here is the log:
Running: 13:05:27
Running: 13:05:27
Running: 13:05:28
Running: 13:05:29
Running: 13:05:30
Running: 13:05:31
Running: 13:05:32
Running: 13:05:33
Running: 13:05:34
SUCCESS: 13:05:35
Continuing: 13:05:35
Continuing: 13:05:36
Continuing: 13:05:37
Continuing: 13:05:38
Continuing: 13:05:39
Continuing: 13:05:40
Continuing: 13:05:41
Continuing: 13:05:42
Continuing: 13:05:43
DONE: 13:05:44