我试图捕获subprocess.Popen
运行的命令的输出,并将其输出到tkinter构建的应用程序中嵌入的xterm终端。我希望命令的输出到达终端并被捕获,以便我可以分析信息。
在另一种情况下,我仅使用subprocess.Popen
运行命令,而不将输出传递给终端。我可以通过包含stdout=subprocess.PIPE, stderr=subprocess.STDOUT
proc_output = subprocess.Popen('ls', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
print(str(proc_output.stdout.read()))
我想我编码的方式可以将输出发送到终端或变量,但不能两者都发送。
对于我的代码示例,终端打开后,我必须在终端中手动键入tty
,然后将输出放在tty
输入字段中。之后,我可以从cmd_entry
运行命令,并将输出发送到终端。
此代码是对here中答案的稍加修改。
from tkinter import *
import subprocess
root = Tk()
termf = Frame(root, height=360, width=625)
termf.pack(fill=BOTH, expand=YES)
wid = termf.winfo_id()
f=Frame(root)
Label(f,text="/dev/pts/").pack(side=LEFT)
tty_index = Entry(f, width=3)
tty_index.insert(0, "1")
tty_index.pack(side=LEFT)
Label(f,text="Command:").pack(side=LEFT)
cmd_entry = Entry(f)
cmd_entry.insert(0, "ls -l")
cmd_entry.pack(side=LEFT, fill=X, expand=1)
def send_entry_to_terminal(*args):
tty="/dev/pts/%s" % tty_index.get()
proc = subprocess.Popen(f'{cmd_entry.get()} <{tty} >{tty} 2> {tty}',
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
print(str(proc.stdout.read())
# cmd(f'{e.get()} <{tty} >{tty} 2> {tty}')
cmd_entry.bind("<Return>", send_entry_to_terminal)
b = Button(f,text="Send", command=send_entry_to_terminal)
b.pack(side=LEFT)
f.pack(fill=X, expand=1)
# cmd(f'xterm -into {wid} -geometry 100x27 -sb -e "tty; sh" &')
subprocess.Popen(f'xterm -into {wid} -geometry 100x27 -sb &', shell=True)
root.mainloop()
我想做的是让任何命令的输出与子进程一起运行以打印到终端,并保存在变量中以供以后处理。然而,现在我只能选一个。
答案 0 :(得分:1)
首先将shell重定向转换为本地Popen
功能:
with open(tty,'r+b',0) as f:
proc=subprocess.Popen(cmd_entry.get(),shell=True,
stdin=f,stdout=f,stderr=f)
if proc.wait(): warn_user(…)
然后,如何保留输出副本应该很明显:
with open(tty,'r+b',0) as f:
proc=subprocess.Popen(cmd_entry.get(),shell=True,
stdin=f,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
out=[]
for l in proc.stdout:
f.write(l)
out.append(l)
out=b"".join(out)
if proc.wait(): warn_user(…)
请注意,该过程随后将具有管道而不是输出(伪)终端,这可能会改变其行为( eg ,ls
打印在单列中,并且git
不使用寻呼机)。如果要保留终端行为,则必须open your own pseudoterminal并将写入其中的输出(可能包括各种控制序列)中继到xterm
创建的输出中。
您可能还想使进程成为({xterm
)终端的前台进程组,以便它可以接收键盘信号;这涉及tcsetpgrp
,并且有些复杂。