我使用此脚本运行交互式VLC bash:
import os
import sys
if len(sys.argv) > 1:
tmp = os.popen('vlc -I rc --novideo --noaudio --rc-fake-tty -q udp://@1.2.3.4:1234').read()
else :
print "Error: no input"
现在在这个bash opend中,我喜欢运行' info'命令,怎么做?
如果在bash我键入
vlc -I rc --novideo --noaudio --rc-fake-tty -q udp://@1.2.3.4:1234
它显示了这个
VLC media player 2.0.8 Twoflower (revision 2.0.8a-0-g68cf50b)
VLC media player 2.0.8 Twoflower
Command Line Interface initialized. Type `help' for help.
>
并等待获取命令。
答案 0 :(得分:2)
这个可以使用纯管道来完成,但它会很难。如果您使用os.popen()
而不是subprocess
,那就更难了。
编写交互式程序脚本的正确方法是使用旨在使其变得简单的更高级库,如pexpect
。然后你就写下这样的东西:
import pexpect
child = pexpect.spawn('vlc -I rc --novideo --noaudio --rc-fake-tty -q udp://@1.2.3.4:1234')
child.expect('>')
child.sendline('info')
response = child.before
然而,更好的解决方案是不以交互模式运行VLC;只需在批处理模式下运行它并传递命令。尽量让你把它作为一个TTY来对待你的输入,这样你就可以试着弄清楚如何在TTY中像人一样行事,这使得事情变得更加困难。
或者,更好的是,使用libVLC代替。从该链接可以看出,它有Python绑定。
如果你真的想以交互方式进行,并且想要通过管道手动完成,那么你必须非常小心。如果您不介意任何意外结果的死锁,您可以这样做:
import subprocess
child = subprocess.Popen(['vlc', '-I', 'rc', '--novideo', '--noaudio',
'--rc-fake-tty', '-q', 'udp://@1.2.3.4:1234'],
stdin=PIPE, stdout=PIPE)
def split_on_prompts():
rbuf = ''
while True:
newbuf = child.stdout.read()
rbuf += newbuf
out, prompt, rest = rbuf.partition('\n>')
if prompt:
yield out
rbuf = rest
if not newbuf:
yield rest
return
output = split_on_prompts()
banner = next(output)
child.stdin.write('info\n')
response = next(output)
# etc.
正如你所看到的,这并不那么有趣。
如果你坚持使用os.open
而不是它被弃用并且使用起来更加痛苦,那么如果你以默认的'r'
模式打开管道,你显然无法写入它像任何其他类似文件的对象一样,当然在最后添加.read()
意味着你甚至不再拥有popen
对象,你只需存储它给你的第一个缓冲区然后泄漏句柄。如果您将其更改为以'r+'
模式打开,如果它在您的平台上有效,并且您存储了popen
对象本身,则可以使用{与上面的subprocess.Popen
对象类似地使用{ {1}}和child.write
代替child.stdin.write child.read
child.stdout.read`。