首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用`stdin=sys.stdin`复制`stdin=PIPE`?

如何用`stdin=sys.stdin`复制`stdin=PIPE`?
EN

Stack Overflow用户
提问于 2016-05-22 06:48:20
回答 1查看 383关注 0票数 5

我有以下代码,其工作原理与预期完全一致:

代码语言:javascript
复制
from subprocess import Popen

process = Popen(
    ["/bin/bash"],
    stdin=sys.stdin,
    stdout=sys.stdout,
    stderr=sys.stderr,
)
process.wait()

我可以交互使用bash,标签工作,等等。

但是,我想控制我发送给stdin的内容,所以我希望下面的内容能够发挥作用:

代码语言:javascript
复制
import os
import sys
from subprocess import Popen, PIPE
from select import select

process = Popen(
    ["/bin/bash"],
    stdin=PIPE,
    stdout=sys.stdout,
    stderr=sys.stderr,
)

while True:
    if process.poll() is not None:
        break

    r, _, _ = select([sys.stdin], [], [])

    if sys.stdin in r:
        stdin = os.read(sys.stdin.fileno(), 1024)
        # Do w/e I want with stdin
        os.write(process.stdin.fileno(), stdin)

process.wait()

但行为就是不一样。我尝试过另一种方法(通过pty):

代码语言:javascript
复制
import os
import sys
import tty
from subprocess import Popen
from select import select

master, slave = os.openpty()
stdin = sys.stdin.fileno()

try:
    tty.setraw(master)
    ttyname = os.ttyname(slave)

    def _preexec():
        os.setsid()
        open(ttyname, "r+")

    process = Popen(
        args=["/bin/bash"],
        preexec_fn=_preexec,
        stdin=slave,
        stdout=sys.stdout,
        stderr=sys.stderr,
        close_fds=True,
    )

    while True:
        if process.poll() is not None:
            break

        r, _, _ = select([sys.stdin], [], [])

        if sys.stdin in r:
            os.write(master, os.read(stdin, 1024))
finally:
    os.close(master)
    os.close(slave)

而且行为非常接近,但选项卡仍然不起作用。好吧,选项卡是正确发送的,但是我的终端没有显示完成,尽管它是由bash完成的。箭头还显示^[[A,而不是遍历历史。

有什么想法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-29 08:07:36

我所需要的只是将我的sys.stdout设置为raw。我还发现了三件事:

  • 我需要恢复sys.stdout上的终端设置
  • subprocess.Popen有一个start_new_session参数,它执行我的_preexec函数所做的工作。
  • select.select接受第四个参数,这是放弃之前的超时。它使我避免在退出后被困在select循环中。

最终代码:

代码语言:javascript
复制
import os
import sys
import tty
import termios
import select
import subprocess

master, slave = os.openpty()
stdin = sys.stdin.fileno()

try:
    old_settings = termios.tcgetattr(sys.stdout)
    tty.setraw(sys.stdout)

    process = subprocess.Popen(
        args=["/bin/bash"],
        stdin=slave,
        stdout=sys.stdout,
        stderr=sys.stderr,
        close_fds=True,
        start_new_session=True,
    )

    while True:
        if process.poll() is not None:
            break

        r, _, _ = select.select([sys.stdin], [], [], 0.2)

        if sys.stdin in r:
            os.write(master, os.read(stdin, 1024))
finally:
    termios.tcsetattr(sys.stdout, termios.TCSADRAIN, old_settings)
    os.close(master)
    os.close(slave)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37371389

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档