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 ?
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:
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.