英文:
How to properly use subprocess.Popen thread's in python?
问题
self.flag = IntVar()
# process for bash 1
self.process1 = subprocess.Popen(["bash"], stderr=subprocess.PIPE, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
# process for bash 2
self.process2 = subprocess.Popen(["bash"], stderr=subprocess.PIPE, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
exit = False
# start threads (stdout and stderror monitor)
threading.Thread(target=self.read_stdout_1).start()
threading.Thread(target=self.read_stderror_1).start()
threading.Thread(target=self.read_stdout_2).start()
threading.Thread(target=self.read_stderror_2).start()
self.frame2 = tk.Frame(self.ws, bg="#777474")
self.frame2.grid(column=0, row=0, padx=(100, 100), pady=(10, 10), sticky="W")
# Start button
self.btnVerify = Button(self.ws, text='Start', command=self.ButtonClick)
self.btnVerify.grid(row=5, columnspan=3, pady=10)
# output text area
self.logArea = tkst.ScrolledText(self.ws, wrap=tk.WORD, width=80, height=20, name="logArea")
self.logArea.grid(padx=(100, 100), pady=(10, 10), row=10, sticky="W")
def read_stdout_1(self):
while not exit:
msg = self.process1.stdout.readline()
self.logArea.insert(INSERT, "process_1 logging start")
self.logArea.insert(INSERT, msg.decode())
self.logArea.insert(END, "\n logging end")
def read_stderror_1(self):
while not exit:
msg = self.process1.stderr.readline()
self.logArea.insert(INSERT, "Error")
self.logArea.insert(INSERT, msg.decode())
self.logArea.insert(END, "\n Error end")
def read_stdout_2(self):
while not exit:
msg = self.process2.stdout.readline()
self.logArea.insert(INSERT, "process_2 logging start")
self.logArea.insert(INSERT, msg.decode())
self.logArea.insert(END, "\nlogging end")
def read_stderror_2(self):
while not exit:
msg = self.process2.stderr.readline()
self.logArea.insert(INSERT, "Error")
self.logArea.insert(INSERT, msg.decode())
self.logArea.insert(END, "\n Error end")
def ButtonClick(self):
print("Button clicked")
# set flag to 1
self.flag = 1
while not exit:
if self.flag == 1:
print("Case 1")
self.process1.stdin.write(r'python C:\path\test1.py'.encode())
self.process1.stdin.flush()
self.flag = 2
elif self.flag == 2:
print("Case 2")
self.process1.stdin.write(r'python C:\path\test2.py'.encode())
self.process1.stdin.flush()
self.flag = 3
elif self.flag == 3:
print("Case 3")
self.process2.stdin.write(r'python C:\path\test3.py'.encode())
self.process2.stdin.flush()
self.flag = 4
elif self.flag == 4:
print("Case 3")
self.process2.stdin.write(r'python C:\path\test4.py'.encode())
self.process2.stdin.flush()
self.flag = 5
else:
break
def run(self):
self.ws.title('Test Script')
self.ws.mainloop()
validator = TKValidator()
validator.run()
英文:
I am writing a python script which will execute some another script from bash
terminals. I need two bash terminal
and execute some script in that bash terminal one by one. After executing the script, I will read the out put messages to a Tkinter text area
. I have designed simple python script which will create 2 process
. I am using thread
to monitor the stdout and stderror for each processes. I am using while loop to hold the process.
Here is the my script
import os
import tkinter as tk
from tkinter import *
import tkinter.scrolledtext as tkst
import subprocess
from subprocess import Popen
import threading
class TKValidator:
def __init__(self):
#create TK
self.ws = Tk()
self.ws.state('zoomed')
self.flag = IntVar()
#process for bash 1
self.process1 = subprocess.Popen(["bash"], stderr=subprocess.PIPE,shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
#process for bash 2
self.process2 = subprocess.Popen(["bash"], stderr=subprocess.PIPE,shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
exit = False
#start threads (stdout and stderror monitor)
threading.Thread(target=self.read_stdout_1).start()
threading.Thread(target=self.read_stderror_1).start()
threading.Thread(target=self.read_stdout_2).start()
threading.Thread(target=self.read_stderror_2).start()
self.frame2 = tk.Frame(self.ws, bg="#777474")
self.frame2.grid(column=0, row=0, padx=(100,100), pady=(10, 10), sticky="W")
#Start button
self.btnVerify = Button(self.ws, text='Start', command=self.ButtonClick)
self.btnVerify.grid(row=5, columnspan=3, pady=10)
#output text area
self.logArea = tkst.ScrolledText(self.ws, wrap= tk.WORD, width=80, height=20, name="logArea")
self.logArea.grid(padx=(100,100), pady=(10, 10) ,row=10, sticky="W")
def read_stdout_1(self):
while not exit:
msg = self.process1.stdout.readline()
self.logArea.insert(INSERT, "process_1 logging start")
self.logArea.insert(INSERT, msg.decode())
self.logArea.insert(END, "\n logging end")
def read_stderror_1(self):
while not exit:
msg = self.process1.stderr.readline()
self.logArea.insert(INSERT, "Error")
self.logArea.insert(INSERT, msg.decode())
self.logArea.insert(END, "\n Error end")
def read_stdout_2(self):
while not exit:
msg = self.process2.stdout.readline()
self.logArea.insert(INSERT, "process_2 logging start")
self.logArea.insert(INSERT, msg.decode())
self.logArea.insert(END, "\logging end")
def read_stderror_2(self):
while not exit:
msg = self.process2.stderr.readline()
self.logArea.insert(INSERT, "Error")
self.logArea.insert(INSERT, msg.decode())
self.logArea.insert(END, "\n Error end")
def ButtonClick(self):
print("Button clicked")
#set flag to 1
self.flag = 1
while not exit:
if self.flag == 1:
print("Case 1")
self.process1.stdin.write(r'python C:\path\test1.py'.encode())
self.process1.stdin.flush()
self.flag = 2
elif self.flag == 2:
print("Case 2")
self.process1.stdin.write(r'python C:\path\test2.py'.encode())
self.process1.stdin.flush()
self.flag = 3
elif self.flag == 3:
print("Case 3")
self.process2.stdin.write(r'python C:\path\test3.py'.encode())
self.process2.stdin.flush()
self.flag = 4
elif self.flag == 4:
print("Case 3")
self.process2.stdin.write(r'python C:\path\test4.py'.encode())
self.process2.stdin.flush()
self.flag = 5
else:
break
def run(self):
self.ws.title('Test Script')
self.ws.mainloop()
validator = TKValidator()
validator.run()
But after exectuing this script, I can see only the output like
Button clicked
I want to run the while loop one by one but it is not working. Can you please suggest, what is the problem here and how can I fix this to work as I expected ?
答案1
得分: 0
这里的简短回答是这行代码:
while not exit:
这里的exit
值始终为True
。尝试打印exit
以查看其实际值:
print(exit, bool(exit))
while not exit:
顺便提一下,由于这个原因,exit
是一个不好的变量名。
更详细的回答是:你为什么要以这种方式进行操作?据我所知(我承认我只是粗略浏览了代码,控制流相当复杂,我不确定我是否理解了它),你的要求是:
- 当单击按钮时,应启动两个脚本
- 当它们完成(或在运行时?)时,它们的输出应打印到文本区域
没有必要通过启动shell、向其stdin提供输入、轮询其stdout等来进行所有这些操作。只需启动一个进程,等待它并将输出放入文本区域,或者在运行时轮询并将输出放入文本区域。如果你想同时从两个子进程输出,你需要解决冲突的逻辑,可能需要使用某种队列。
如果你需要与脚本进行交互,我强烈建议你使用pexpect。
英文:
The short answer here is this line:
while not exit:
The value of exit
here is always True
. Try printing exit to find out what it actually is:
print(exit, bool(exit))
while not exit:
Incidentally exit
was a bad variable name for this reason.
The longer answer is: why are you doing things this way? As far as I can tell (I admit I only skimmed the code and the control flow manages to be sufficiently convoluted that I'm not sure I followed it) your requirements are:
- when a button is clicked, two scripts should be launched
- when they are finished (or whilst running?), their outputs should be printed to the textarea
There is no reason to mess about with starting shells, feeding to their stdin, polling their stdout, etc, for any of this. Just launch a process, join it and drop the output into the textarea or poll it whist running and output to the textarea. If you want to output from two subprocesses at once you need deconfliction logic: probably a queue of some description.
If you need to interact with the scripts I strongly recommend you use pexpect.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论