Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用python';s pty创建实时控制台_Python_Shell_Subprocess_Pty - Fatal编程技术网

使用python';s pty创建实时控制台

使用python';s pty创建实时控制台,python,shell,subprocess,pty,Python,Shell,Subprocess,Pty,我正在尝试创建一个执行环境/shell,它将在服务器上远程执行,通过要在浏览器中呈现的套接字将标准输出err流式传输到服务器中。我目前已经尝试了使用子流程的方法。使用管道运行。问题是我在进程完成后得到了标准输出。我想要实现的是一行一行的伪终端实现 我当前的实现 test.py 在壳里 >>> import subprocess >>> result = subprocess.run(['python3', 'test.py'], stdout=subproce

我正在尝试创建一个执行环境/shell,它将在服务器上远程执行,通过要在浏览器中呈现的套接字将标准输出err流式传输到服务器中。我目前已经尝试了使用
子流程的方法。使用
管道运行
。问题是我在进程完成后得到了标准输出。我想要实现的是一行一行的伪终端实现

我当前的实现

test.py

在壳里

>>> import subprocess
>>> result = subprocess.run(['python3', 'test.py'], stdout=subprocess.PIPE)
>>> print(result.stdout.decode('utf-8'))
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world

如果我试着用
pty
来尝试这个简单的实现,那怎么做呢?

我肯定在某个地方有一个复制品,但我不能很快找到它

process=subprocess.Popen(cmd,stderr=subprocess.PIPE,stdout=subprocess.PIPE,bufsize=0)
对于输入输出iter(process.stdout.readline,b“”):
打印(输出)

如果你在Windows上,那么你将在很长一段时间内进行一场艰苦的战斗,我为你(在那里)所忍受的痛苦感到抱歉。但是,如果您在Linux上,则可以使用该模块。Pexpect允许您生成一个后台子进程,您可以与它执行双向通信。这对于所有类型的系统自动化都很有用,但ssh是一个非常常见的用例

import pexpect

child   = pexpect.spawn('python3 test.py')
message = 'hello world'

while True:
    try:
        child.expect(message)
    except pexpect.exceptions.EOF:
        break
    input('child sent: "%s"\nHit enter to continue: ' %
         (message + child.before.decode()))

print('reached end of file!')
我发现创建一个类来处理诸如ssh连接之类的复杂事情非常有用,但是如果您的用例足够简单,可能不合适或不必要。pexpect.before的方式是bytes类型,省略了您正在搜索的模式可能会很尴尬,因此创建一个至少能为您处理此问题的函数可能是有意义的

def get_output(child, message):
    return(message + child.before.decode())
如果要向子进程发送消息,可以使用child.sendline(line)。有关更多详细信息,请查看我链接的文档


我希望我能帮上忙

我不知道是否可以在浏览器中渲染,但您可以运行类似于模块的程序,以便立即获得标准输出,如下所示:

import importlib
from importlib.machinery import SourceFileLoader

class Program:

    def __init__(self, path, name=''):
        self.path = path
        self.name = name
        if self.path:
            if not self.name:
                self.get_name()
            self.loader = importlib.machinery.SourceFileLoader(self.name, self.path)
            self.spec = importlib.util.spec_from_loader(self.loader.name, self.loader)
            self.mod = importlib.util.module_from_spec(self.spec)
        return

    def get_name(self):
        extension = '.py' #change this if self.path is not python program with extension .py
        self.name = self.path.split('\\')[-1].strip('.py')
        return

    def load(self):
        self.check()
        self.loader.exec_module(self.mod)
        return

    def check(self):
        if not self.path:
            Error('self.file is NOT defined.'.format(path)).throw()
        return

file_path = 'C:\\Users\\RICHGang\\Documents\\projects\\stackoverflow\\ptyconsole\\test.py'
file_name = 'test'
prog = Program(file_path, file_name)   
prog.load()
您可以在test.py中添加sleep以查看差异:

from time import sleep

def greeter():
    for i in range(10):
        sleep(0.3)
        print('hello world')

greeter()

如果您的应用程序将与多个任务异步工作,比如从标准输出读取数据,然后将其写入websocket,我建议使用

下面是一个运行进程并将其输出重定向到websocket的示例:

import asyncio.subprocess
导入操作系统
从aiohttp.web导入(应用程序、响应、WebSocketResponse、WSMsgType、,
运行(应用程序)
websocket上的异步定义(请求):
#准备aiohttp的websocket。。。
resp=WebSocketResponse()
等待响应准备(请求)
# ... 并存储在全局字典中,以便在关机时关闭
request.app['sockets'].append(resp)
process=wait asyncio.create_subprocess_exec(sys.executable,
“/tmp/test.py”,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
bufsize=0)
#将从stdout和stderr的读取安排为异步任务。
stdout\u f=asyncio.sure\u future(p.stdout.readline())
stderr\u f=asyncio.sure\u future(p.stderr.readline())
#返回代码将在进程终止时设置。
p.returncode为无:
#在stdout或stderr中等待一行。
wait asyncio.wait((stdout\u f,stderr\u f),在=asyncio.FIRST\u完成时返回)
#若任务完成,则该行可用。
如果stdout\u f.done():
line=stdout\u f.result().encode()
stdout\u f=asyncio.sure\u future(p.stdout.readline())
等待ws.send_str(f'stdout:{line})
如果标准已完成():
line=stderr_f.result().encode()
stderr\u f=asyncio.sure\u future(p.stderr.readline())
等待ws.send_str(f'stderr:{line})
返回响应
异步def on_关机(应用程序):
对于应用程序中的ws['sockets']:
等待ws.close()
异步定义初始化(循环):
app=应用程序()
应用程序['sockets']=[]
app.router.add_get('/',在_websocket上)
app.on\u shutdown.append(on\u shutdown)
返回应用程序
loop=asyncio.get\u event\u loop()
app=loop。运行_直到_完成(init())
运行应用程序(应用程序)

它使用并基于和示例。

检查:尝试使用
bufsize=1
参数对子进程设置行缓冲区,并使用
iter(result.stdout.readline,b'')
读取包装在True循环中的stdout。这仍将等待
cmd
完成,然后for循环将启动。我想要更多的异步实现,这就是为什么我想了解更多关于
pty
的信息,这应该是实时流式的。。。如果您没有发现缓冲区大小为零,则可能需要将其设置为零case@IshanKhare>这将在实时流。
Popen
函数在后台启动程序并立即返回。程序输出的任何内容都将立即读取。但是请注意,读取是缓冲的,因此一旦读取了足够大的块,读取就会返回(这就是为什么如果使用太简单的示例进行测试,您可能会认为它会等待)。如果确实希望以牺牲性能为代价进行完全实时读取,则可以使用
bufsize=0禁用缓冲。
from time import sleep

def greeter():
    for i in range(10):
        sleep(0.3)
        print('hello world')

greeter()