【问题标题】:Supply stdin input to subprocess.Popen() after execution of the process had begun ( and before it had finished )在进程执行开始之后(在完成之前)向 subprocess.Popen() 提供标准输入
【发布时间】:2021-01-25 13:25:41
【问题描述】:

我正在用 Python3 中的远程 shell 实用程序制作一个程序,使用套接字和子进程。到目前为止一切正常,但我遇到了一个我找不到解决方案的问题。这是我的服务器脚本上的代码,它执行从客户端接收到的命令:

process = subprocess.Popen(client_buffer.decode('utf-8').split(), stdout = subprocess.PIPE) # Creating a process
        while True: # Reading and sending the stdout from the process in realtime
            shell_output = process.stdout.readline() # Read a line from stdout
            return_code = process.poll()
            print(shell_output)
            print(return_code)
            if shell_output.decode('utf-8') == '' and return_code is not None: 
                #print("Process execution complete. Sending user prefix")
                send(client, ("<#" + color.user + getpass.getuser() + color.endc + "@" + color.dir + cwd() + color.endc + ">").encode('utf-8'))
                break
            elif shell_output: 
                # Process execution incomplete, signaling to client with code 2
                send(client, int_to_bytes(2))
                # And sending the next line of stdout
                send(client, shell_output)

一切正常,我很满意,但有一个限制我不知道如何消除。 也就是说,我可以轻松地向服务器提供带有参数的命令,服务器将执行它并将输出发回,这很好,但是如果由命令启动的程序要求额外的输入(例如“(y / n )" 问题)在流程执行结束之前(执行中),我不知道如何向流程提供输入。

我可以用 subprocess.Popen() 做到这一点吗?任何线索都会有所帮助,我提前感谢您。我忘了补充,这个程序是用来在 Linux 中使用的。

P.S 任何我在代码示例中没有提供的定义/声明的函数和变量都无关紧要,但是可以在我的github 上找到该项目,以防有人想查看更多代码 em>

【问题讨论】:

    标签: python python-3.x subprocess


    【解决方案1】:

    首先我认为readline() 在这里是有问题的,除非程序的提示以换行符()结束:程序写入提示并等待答案,而readline() 正在等待行尾.我认为您将不得不改用read() 并做一些更底层的事情。

    要真正向程序发送一些东西,我想你可以写信给process.stdin

    看看 pexpect (https://pexpect.readthedocs.io)。我不确定它是否适合您的用例,但如果适合,它可以让生活更轻松,因此值得努力找出答案。

    需要考虑的另一件事是:许多命令都可以选择使其在没有额外提示的情况下运行,以防止您在从另一个程序运行时遇到问题。如果您正在使用的程序是这种情况,那将是迄今为止最简单的解决方案。

    【讨论】:

    • +1 我认为这更好地实现了 @czyngis 真正寻找的东西,并且似乎回答了他们将遇到的所有不同的痛苦,尤其是对于 pexpect(认为它有一些他们将分享的痛苦,例如occasionally missing output and bonus characters) .. 真的,选择所有 CLI 参数开始并运行到完成似乎总是更好(即使这涉及使用只询问用户输入的向导包装在真正开始跑步之前)
    【解决方案2】:

    通过提供stdin arg,您可以访问subprocess'd processes' stdin

    p = subprocess.Popen(
        ...
        stdin=subprocess.PIPE,
        ...
    )
    
    p.stdin.write("foo")
    

    您也可以只将输入发送到myprocess.communicate(),但它会一直阻塞直到完成!

    ...
    stdout, stderr = p.communicate(myinput)
    

    如果您提前知道它们会是什么,您可以发送大量输入来回答许多问题(例如友好的"y\n" * 100

    【讨论】:

    • 当我开始写答案时,我实际上并没有意识到这是直接可能的(我已经编写了大量的交互代码并看到了一些使用逻辑,例如 3rd-party interact module ),但似乎是您可以直接写入 Popen 进程对象的 stdin,只要在创建期间提供了 arg 并利用 communicate()(谢天谢地,这是我必须管理的全部)
    • 我会尽快检查此代码,没想到反应这么快,明天晚上我会坐下来试试这个,如果它确实有效,请将您的问题标记为正确这个。我不知道这怎么能逃避我,应该在开始工作之前更努力地阅读文档。似乎正是我正在寻找的(当然是第一种方法)
    • 小心龙。直接使用 proc.stdin.write 很容易死锁。考虑改用pseudo tty
    • 确实是龙.. 这就是pexpect (正如 @Roel Schroeven 在另一个答案中所建议的那样)does under the hood
    【解决方案3】:

    好吧,首先是明显而微不足道的错误:

    shell_output = process.stdout.readline()
    

    不!您只能写入标准输入并从标准输入读取。

    stdout = standard output
    stdin = standard input
    

    将管道视为真正的管道。 输出流入 输入另一个命令。

    【讨论】:

    • 能否详细说明?
    猜你喜欢
    • 1970-01-01
    • 2015-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    • 2019-12-05
    • 1970-01-01
    • 2023-04-10
    相关资源
    最近更新 更多