python - 循环标准输出时轮询子进程完成
问题描述
我正在编写一个脚本,它以不可预测的大小产生输出,我想在脚本完成时从循环内部知道。
这是代码:
#!/usr/bin/env python3
import subprocess
import shlex
def main():
cmd = 'bash -c "for i in $(seq 1 15);do echo $i ;sleep 1;done"'
print(cmd)
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE,
universal_newlines=True)
for line in p.stdout:
print(f"file_name: {line.strip()}")
print(p.poll())
if __name__ == "__main__":
main()
p.poll()
即使在最后一次迭代中也总是如此,这None
是有道理的,因为在echo
它sleep
s 1 秒之后,才移动到下一次迭代并完成。
有什么办法让它工作吗?
解决方案
您已经确定了问题所在,也就是说,在子进程输出最后一行之后,它仍将继续运行一秒钟,因此当程序处于循环中时,将始终可以看到该程序正在运行。即使您将调用移到poll
循环之外,您也可能需要稍等片刻才能让子进程在输出其最终消息后有机会终止(我已经减小了循环大小——生命太短了):
#!/usr/bin/env python3
import subprocess
import shlex
import time
def main():
cmd = 'bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"'
print(cmd)
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, universal_newlines=True)
for line in p.stdout:
print(f"file_name: {line.strip()}", flush=True)
print(p.poll())
time.sleep(.1)
print(p.poll())
if __name__ == "__main__":
main()
印刷:
bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"
file_name: 1
file_name: 2
file_name: 3
file_name: 4
file_name: 5
None
0
要在循环内部“让它工作”,需要对子流程内部发生的事情有特殊的了解。根据前面的代码,我们需要:
#!/usr/bin/env python3
import subprocess
import shlex
import time
def main():
cmd = 'bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"'
print(cmd)
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, universal_newlines=True)
for line in p.stdout:
# has to be greater than the sleep time in the subprocess to give the subprocess a chance to terminate
print(f"file_name: {line.strip()}", flush=True)
time.sleep(1.1)
print(p.poll())
if __name__ == "__main__":
main()
印刷:
bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"
file_name: 1
None
file_name: 2
None
file_name: 3
None
file_name: 4
None
file_name: 5
0
但这几乎不是一个实际的解决方案。人们不得不问进行这项民意调查的原因是什么?除非您愿意sleep
在读取之后包含调用,否则它不会提供任何有用的信息,因为在子进程完成最后一次写入及其终止之后总会有一些延迟,并且这些sleep
调用通常是浪费的。您应该一直阅读,直到没有更多输出,然后执行 ap.wait()
以等待子进程终止,但这是您的选择:
#!/usr/bin/env python3
import subprocess
import shlex
def main():
cmd = 'bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"'
print(cmd)
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, universal_newlines=True)
for line in p.stdout:
print(f"file_name: {line.strip()}", flush=True)
p.wait()
if __name__ == "__main__":
main()
推荐阅读
- android - 如果 android jetpack compose 中的单词太长,则用连字符打破句子行
- qt - 当有委托时,使 QTableView 的 Key_Up 和 Key_Tab 行为相同
- python - 如何在不同环境中通过新终端执行命令
- c# - Firestore collectionGroup 查询在 Unity 中返回空结果
- com - .NET WebBrowser 粘贴安全限制
- c++ - C ++:重新绑定泛型类型的变量
- flutter - 在 Flutter Web 视图中控制 Facebook 视频
- node.js - 是否有更好的方法来授予对 AWS Lambda 的访问权限,以便它可以调用 AWS 简单电子邮件服务?
- eclipse - 我的 Mavens pom.xml 文件中出现此错误“无法初始化类 org.apache.maven.plugin.war.util.WebappStructureSerializer”,请问有什么解决方案吗?
- c++ - C++ Cereal:如何在不知道其 polymorphic_id 的情况下加载多态类?