【问题标题】:Getting a shell script to wait for a specific response from python program获取 shell 脚本以等待来自 python 程序的特定响应
【发布时间】:2021-12-06 21:11:57
【问题描述】:

我正在尝试编写一个调用 python 程序的脚本,暂停直到程序输出特定消息(而不是程序结束时),然后继续。

如果我有像这样无限期运行的 example.py:

doSomething()
print('I did something')
doSomethingElseForever()

我想要一个类似这样的脚本:

echo "Running python program"
python3 example.py &
waitForOutput("I did something")
echo "Python program did something, it's still running in the background"
doSomeMoreScriptStuff

理想情况下,我只运行脚本,它会启动 example.py,暂停直到 example.py 输出“我做了某事”,然后继续启动更多程序或其他什么,而不停止 example.py(因此 & )。

我在 Ubuntu BTW 中工作。

编辑:我认为目前在我的特定应用程序中,我可以更改我的 python 脚本来创建文件而不是 print(),但是为了学习(而且因为这似乎是一种复杂的做事方式) ,假设我无法编辑 python 文件。所以我需要处理的只是 print() 语句的已知输出。

【问题讨论】:

  • 我注意到您添加了python 标签,那么您愿意接受 Python 中的解决方案吗?如果是这样,天真的答案就是分解 Python 脚本,但假设 doSomething 和 doSomethingElseForever 没有任何相互依赖关系。
  • 我之前看到过那个帖子,但我认为这不是我想要的。第一个答案不是我想要的,因为(我认为)它正在检查文件中的更改,这不是我正在做的,第二个答案可能有效,但我很难弄清楚如何在我的上下文中使用它。不幸的是,我无法将 doSomething() 和 doSomethingElseForever() 分开,因为我实际上正在寻找的消息是确认无限期运行的进程已经开始。
  • 你为什么不改变你的 Python 脚本,让它在完成第一件事后创建一个文件?然后您的 shell 脚本可以简单地等待该文件存在。
  • @Josh 我认为最重要的两个答案是说您可以将进程的输出重定向到一个文件,然后使用tail -f ... | grep -q ... 观察输出。虽然我自己从来没有做过这样的事情。万一这些解决方案都不适合您,您可以edit 解释和强调您的情况有何不同。

标签: shell script


【解决方案1】:

您可以使用pexpect 执行此操作。我启动了一个调用pexpect.spawn() 的线程来运行您的子脚本。它等待您想要的输出,然后设置一个事件,以便主程序知道该事件已发生。然后它等待子程序退出,这反过来又允许主程序退出:

#!/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')

我用这个 example.sh 作为你调用的 Python 脚本的模型:

#!/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"

这是日志:

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

【讨论】:

  • 我希望在脚本本身中做到这一点,但实际上我看不出有任何理由必然是这种情况。我会尝试 pexpect,看起来这对我正在尝试做的事情有用。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-23
  • 1970-01-01
  • 1970-01-01
  • 2020-07-31
  • 2014-10-21
  • 1970-01-01
  • 2017-03-26
相关资源
最近更新 更多