Python子流程管道中的多个输入(使用stdin或communicate)
我一直在寻找上述问题的答案 Popen命令不应返回任何内容,它只是询问“是否要继续?”(是)以及从本地数据库获取的“管理员密码” 当前的代码状态是:一切正常,但要求我进行第二次输入,第一次输入通过Python子流程管道中的多个输入(使用stdin或communicate),python,subprocess,stdin,popen,Python,Subprocess,Stdin,Popen,我一直在寻找上述问题的答案 Popen命令不应返回任何内容,它只是询问“是否要继续?”(是)以及从本地数据库获取的“管理员密码” 当前的代码状态是:一切正常,但要求我进行第二次输入,第一次输入通过 我使用的是Ubuntu服务器(带有Python-u) 尝试在每次标准写入后刷新 尝试通信(有问题,代码循环次数不限) 尝试过pexpect,但也有问题,我想Popen在我的条件下更合适 所以,我愿意接受建议,并愿意尝试你的帮助。任何帮助都将不胜感激 #Input 1
- 我使用的是Ubuntu服务器(带有Python-u)
- 尝试在每次标准写入后刷新
- 尝试通信(有问题,代码循环次数不限)
- 尝试过pexpect,但也有问题,我想Popen在我的条件下更合适
#Input 1
p = Popen(["foo", "bar"], stdin=PIPE, universal_newlines=True)
try:
p.stdin.write('yes' + linesep)
except IOError as e:
if e.errno == errno.EPIPE or e.errno == errno.EINVAL:
break
else:
raise
p.stdin.flush()
#Input 2
try:
p.stdin.write(KeyPass + linesep)
except IOError as e:
if e.errno == errno.EPIPE or e.errno == errno.EINVAL:
break
else:
raise
p.stdin.flush()
p.stdin.close()
p.wait()
它不回显密码,也不回显星号
这意味着您无法通过stdin
。你想做的事情是不可能的
查看是否有其他方法可以在命令行或环境中为其提供密码,或避免为其提供密码(例如,使用ssh
可以交换密钥,而不是传递密码)
如果不是,您唯一的选择就是给它一个伪TTY,而不是一个常规管道。(即使这样也不能保证有效,但很可能有效,值得一试。)
有三种方法可以从Python和模块中实现这一点。从理论上讲,forkpty
是最特定于平台的,但在实践中,因为pty
只在Linux上进行测试,openpty
要求您做其他特定于平台的事情来实际使用它,所以我从forkpty
开始。代码如下所示:
pid, fd = os.forkpty()
if not pid:
# We're in the child here, but we still have to launch the program
os.execlp('foo', 'bar')
# This code is still in the parent.
现在,家长可以使用os.read(fd)
和os.write(fd)
与孩子交谈,孩子将看到它来自TTY。当子项完成时,您必须os.waitpid(pid)
it。请记住,这里处理的是低级文件I/O,没有Unicode解码,没有通用换行符,最重要的是,没有缓冲。这可能很难处理,但你必须处理它
当然,您也可以使用像pexpect
这样的库,它可以使用PTY并隐藏所有细节。我不知道你为什么抵制这个想法,但是当你在尝试处理forkpty
时感到沮丧时,也许再给它一次机会
它只是询问“您想继续吗?”(是)和“管理员密码”
如果子进程询问“…继续”,则回答“是”
,并在提示时写入密码:
import pexpect # $ pip install pexpect
output, status = pexpect.run('foo bar',
events={r'continue\?': 'yes\n', 'password': 'p4$$W__rd\n'},
withexitstatus=1)
pexpect
确保即使子进程直接写入/读取终端(进程外部的stdout/stdin),您也可以看到它的输出并接收您的输入。您可以使用communicate()
而不是write()
如果您试图驾驶交互式应用程序,
Popen
并不比pexpect
更适合您的情况。告诉我们你尝试了什么,出了什么问题;几乎可以肯定,这是一个更简单的修复方法。此外,它要求“从本地数据库获取的“管理员密码”。通常,当程序要求输入密码时,它们要么从TTY而不是stdin读取,要么在stdin不是TTY或无法设置为NOECHO时拒绝继续,要么调用libpam
或类似程序,而不是自己读取密码。如果在命令行上运行此命令,输入密码时是否会回显?(此外,您没有读取标准输出,因此在发送密码之前没有等待提示,如果它在提示之前丢弃输入,则会破坏它,许多密码输入都会这样做。)即使发送了yes输入,您也看不到任何内容,但它可以工作,您可以尝试其他任何内容,然后它不会要求管理员密码。我也不想看到任何东西,当我的工作完成时,我不会打印输入或输出,我现在正在调试。此外,还使用minidom从XML数据库解析管理员密码。因此,它被设置为KeyPass变量。对不起,我不知道你说的细节。这是一个简单的应用程序,popen应该足够了。同样,当你在命令行上运行应用程序时,它是否会回显密码?如果你在提示符前开始键入,它会忽略你在提示符前键入的任何内容吗?这就像更改*nix系统的密码一样。它不回显密码,也不回显星号。很抱歉在我的第一次评论中出现误解。我应该再次尝试pexpect,然后再回到这个话题。在与pexpect合作几个小时后,我终于成功了。谢谢你,abarnert。它不会工作,否则问题中的代码会工作。密码很可能是直接从终端读取的。请参阅,对于使用Windows的用户,run()
将不起作用。它依赖于Unix伪终端。从版本4开始,建议使用(这是实验性的)。@AndrewMyers OP使用Ubuntu。在回答问题时,Pexpect根本不支持Windows<如果程序直接从控制台读取密码(getwch/ReadConsole API-Windows模拟使用pty),code>PopenSpawn将不起作用。
p.communicate(input='{}\n{}'.format('yes', KeyPass).encode('utf-8'))