Python 如何执行命令并读取/写入其STDIN/TTY(一起)?

Python 如何执行命令并读取/写入其STDIN/TTY(一起)?,python,subprocess,pty,Python,Subprocess,Pty,我已经看到了关于如何单独做这些事情的例子和问题。但在这个问题上,我试着把它们全部结合起来 基本上,我的情况是,我有一个命令,需要我写入它的STDIN,从它的STDOUT读取,并回答它的TTY提示。只需执行一次命令即可完成所有操作。这并不重要,但如果您好奇的话,命令是scrypt enc-out.enc 限制:必须是纯Python 问题:怎么做 我试过这些: 导入pty 导入操作系统 导入子流程 master,slave=pty.openpty() p=subprocess.Popen(['su

我已经看到了关于如何单独做这些事情的例子和问题。但在这个问题上,我试着把它们全部结合起来

基本上,我的情况是,我有一个命令,需要我写入它的STDIN,从它的STDOUT读取,并回答它的TTY提示。只需执行一次命令即可完成所有操作。这并不重要,但如果您好奇的话,命令是
scrypt enc-out.enc

限制:必须是纯Python

问题:怎么做


我试过这些:

导入pty
导入操作系统
导入子流程
master,slave=pty.openpty()
p=subprocess.Popen(['sudo','ls','-lh'],stdin=slave,stdout=master)
x=操作系统读取(主)
打印(x)
stdout,stderr=p.communicate(b'lol\r\n')
导入pty
导入操作系统
导入系统
导入子流程
def读取(fd):
数据=操作系统读取(fd,1024)
data_str=data.decode()
如果数据搜索('[sudo]密码')==0:
数据_str='密码plz:'
系统标准写入(数据存储)
sys.stdout.flush()
def写入(fd):
x='lol\r\n'
对于x.encode()中的b:
操作系统写入(fd,b)
p.spawn(['sudo','ls','-lh'],读,写)
目标是完全包装TTY提示,以便用户看不到它们,同时为TTY输入提供一些密码,使
sudo
感到高兴

基于这一目标,由于各种原因,这些尝试都不起作用


但更糟糕的是:假设它们工作,我如何才能将进程的某些内容提供给它的STDIN和TTY输入?让我困惑的是,
Popen
示例逐字说明
stdin
被映射到TTY(pty),那么它如何知道哪个是哪个?它如何知道某些输入是用于标准输入而不是TTY输入?

免责声明:
详细讨论这个主题需要大量的文本,因此我将尽量简化内容以保持简短。我将尽可能多地加入“供进一步阅读”的链接

简而言之,只有一个输入流,即STDIN。在正常端子中,STDIN连接到TTY。因此,shell将读取您“在TTY上键入”的内容。然后,贝壳决定如何处理它。如果有一个程序正在运行,它将发送给该程序的STDIN。
如果在python中使用
Popen
运行某个程序,则不会有tty。通过执行以下操作,您可以轻松检查:

从子流程导入Popen,管道
p=Popen(“tty”,标准输入=管道,标准输出=管道,标准输出=管道)
o、 e=p.沟通
打印(o)
它将产生以下输出:
b'不是tty\n'

但是scrypt如何尝试使用TTY呢?因为它就是这样做的。
您必须查看手册页和代码,才能找到答案

如果未给出-p,则scrypt从其控制终端读取密码短语,否则从stdin读取密码短语

实际上,它只是打开了
/dev/tty
(请看)。这是存在的,即使进程没有TTY。因此,它可以打开它,并尝试从中读取密码

您现在如何解决您的问题?
嗯,在这种情况下这很容易。检查手册页中的
-P
参数。
以下是一个工作示例:

从子流程导入Popen,管道
p=Popen(“scrypt enc-p-out.enc”,stdin=PIPE,stdout=PIPE,stderr=PIPE,universal\u newlines=True,shell=True)
p、 通信(“pwd\nteststring”)
这将用密码“pwd”加密字符串“teststring”

有很多关于TTY等的“黑客”,但你应该避免这些,因为它们可能会产生意想不到的结果。例如,启动一个shell并运行
tty
,然后运行第二个shell并使用
tty
命令的输出运行
cat
(例如
cat/dev/pts/7
)。然后在第一个shell中键入一些内容,观察发生了什么。
如果不想尝试,一些字符将出现在第一个shell中,一些字符将出现在第二个shell中


检查并了解TTY是什么以及它来自何处。

请添加一些您迄今为止尝试过的信息。@toydarian完成了。您尝试过您的示例吗?因为
-P
不能与
-
scrypt
一起使用。这种组合导致错误
scrypt:无法从标准输入中同时读取密码和输入文件。它为我工作me@caveman我有以下scrypt版本:
scrypt 1.2.0-head
interest<代码>scrypt 1.3.1
此处。我现在正在考虑用临时目录中的命名管道替换
-
,希望在
scrypt
之前没有其他应用程序读取它。或者,使用
argon2id
从密码派生一个密钥(与STDIN一起使用),然后将该派生密钥与Python中任何好的sharedkey密码一起使用。@caveman为什么不在收到EOF之前读取Python中的输入,将其写入临时文件并加密?