捕获传递到嵌入式终端的命令的标准输出

时间:2019-04-24 22:40:04

标签: python

我试图捕获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()

我想做的是让任何命令的输出与子进程一起运行以打印到终端,并保存在变量中以供以后处理。然而,现在我只能选一个。

1 个答案:

答案 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,并且有些复杂。