【问题标题】:run command in interactive opend bash with python使用 python 在交互式 opend bash 中运行命令
【发布时间】:2014-08-03 07:33:59
【问题描述】:

我使用这个脚本来运行交互式 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 中我喜欢运行“信息”命令,怎么做?

如果我在 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.
>

它等待获取命令。

【问题讨论】:

  • 第一个问题是,你为什么用os.popen?这是一个被弃用的函数,它从来都不容易使用,并且在不同的时间都有严重的错误。在 Python 2.6 之前有使用它的借口,但从 2.6+ 开始,你永远不应该使用它。这就是为什么docs 和交互式帮助都说不要使用它的原因。

标签: python bash shell os.system


【解决方案1】:

这个可以用纯管道来完成,但这会很困难。如果你使用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' 模式打开管道,您显然无法写入它,就像任何其他文件一样-like 对象,当然最后加上.read() 意味着您甚至不再拥有popen 对象,您只是存储了它给您的第一个缓冲区,然后泄漏了句柄。如果您将其更改为以'r+' 模式打开,如果这适用于您的平台,并且您存储popen 对象本身,您可以使用它类似于上面的subprocess.Popen 对象,使用child.writechild.read而不是 child.stdin.writeandchild.stdout.read`。

【讨论】:

    猜你喜欢
    • 2012-07-12
    • 2021-08-01
    • 2012-10-23
    • 2015-02-19
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    相关资源
    最近更新 更多