python 2.7-与mpg123的子流程控制交互

python 2.7-与mpg123的子流程控制交互,python,subprocess,pty,communicate,Python,Subprocess,Pty,Communicate,几周前,我在这里问了一个与此相关的问题: 多亏了那里的帮助,我当时能够做我需要的事情。(没有调用q,但终止了子进程以停止它)。##Heading## 现在,我似乎又陷入了一片混乱 from subprocess import Popen, PIPE, STDOUT p = Popen(["mpg123", "-C", "test.mp3"], stdout=PIPE, stdin=PIPE, stderr=STDOUT) #wait a few seconds to e

几周前,我在这里问了一个与此相关的问题:

多亏了那里的帮助,我当时能够做我需要的事情。(没有调用q,但终止了子进程以停止它)。##Heading## 现在,我似乎又陷入了一片混乱

    from subprocess import Popen, PIPE, STDOUT
    p = Popen(["mpg123", "-C", "test.mp3"], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
    #wait a few seconds to enter this, "q" without a newline is how the controls for the player work to quit out if it were ran like "mpg123 -C test.mp3" on the command line
    p.communicate(input='q')[0]
就像以前一样,我需要它能够退出mpg123,就像它的标准控件一样(比如按'q'退出,或者按'-'调低音量,+'调高音量等等),现在我使用上面的代码,理论上应该可以工作,它可以与类似的程序一起工作。有人知道我可以通过子进程使用内置在mpg123中的控件(通过使用“mpg123-C whatever.mp3”可以访问的控件)的方法吗?终止是不够的,因为我将需要控制^_^

编辑:非常感谢abarnert给出的惊人答案=) 好的,新代码只是abarnert答案的一个稍加修改的版本,但是mpg123似乎不接受这些命令

    import os
    import pty
    import sys
    import time

    pid, fd = os.forkpty()
    if pid:
        time.sleep(5)
        os.write(fd, 'b') #this should've restarted the file
        time.sleep(5)
        os.write(fd, 'q') #unfortunately doesn't quit here =(
        time.sleep(5) # quits after this is finished executing
    else:
        os.spawnl(os.P_WAIT, '/usr/bin/mpg123', '-C', 'TEST file.mp3')

如果你真的需要这些控件,你不能只使用
Popen

mpg123
仅当其stdin是tty时启用终端控制,而不是当它是文件或管道时启用终端控制。这就是为什么你会在横幅上看到这句话:

Terminal control enabled, press 'h' for listing of keys and functions.
Popen
(和
子流程
,以及它所构建的POSIXAPI)的全部要点就是管道

那么,你能做些什么呢


在linux上,您可以使用该模块。它也可以在其他*nix平台上工作,但即使它被构建并包含在您的stdlib中,也可能无法工作。正如文件所说:

因为伪终端处理高度依赖于平台,所以只有针对Linux的代码才可以这样做。(Linux代码应该可以在其他平台上运行,但尚未经过测试。)

它肯定在2.7和3.3版本的*BSD平台上运行,文档中的示例似乎在Mac OS X和FreeBSD上都能运行……但这就是我所检查的


同时,大多数POSIX平台至少会有,这并不难,所以这里有一个简单的程序,它播放作为第一个参数传递的歌曲的前5秒:

import os
import pty
import sys
import time

pid, fd = os.forkpty()
if pid:
    time.sleep(5)
    os.write(fd, 'q')
else:
    os.spawnl(os.P_WAIT, # mode
              '/usr/local/bin/mpg123', # path
              '/usr/local/bin/mpg123', '-C', sys.argv[1]) # args

注意,我在上面使用了
os.spawnl
。这可能不是你在真正的程序中想要的;这是出于教学目的,鼓励您阅读文档(以及相应的手册页)并理解这一系列函数

如前所述,这不使用
PATH
环境变量,因此需要指定程序的完整路径。您可以使用
spawnlp
而不是
spawnl
来修复此问题

另外,
spawn
可以(事实上,总是这样,尽管文档并不完全清楚)执行另一个fork来执行子级。这确实不是必需的,但是
spawn
会执行一些如果您只是调用
exec
就需要手动执行的操作。如果您知道自己在做什么,您很可能希望使用
execl
(或
execlp
)而不是
spawnl

只要小心,您甚至可以使用
subprocess
中的大部分功能(不要创建任何管道,并且记住,最终会执行两个
fork
s,因此请确保正确设置父/子关系)

还要注意,您需要将路径传递到
mpg123
两次,一次作为路径,然后一次作为子程序的
argv[0]
。您也可以第二次通过mpg123。或者,理想情况下,当您从shell运行它时,查看
ps
所说的内容,并传递它。无论如何,您必须将某些内容作为
argv[0]
传递;否则,
-C
将成为
argv[0]
,这意味着mpg123不会认为您给了它一个
-C
标志来启用控制键,而是将其重命名为
-C
,并在没有标志的情况下运行它

无论如何,你真的需要阅读文档来理解这些函数的作用,而不是把它们当作你不懂的魔法代码。因此,我故意使用最简单的解决方案来鼓励这一点



在Windows上,没有所谓的
pty
,也没有办法使用Python内置的工具来实现这一点。您需要使用各种第三方库中的一种来控制cmd.exe控制台(也称为DOS提示符)。

如果您确实需要这些控件,您不能只使用
Popen

mpg123
仅当其stdin是tty时启用终端控制,而不是当它是文件或管道时启用终端控制。这就是为什么你会在横幅上看到这句话:

Terminal control enabled, press 'h' for listing of keys and functions.
Popen
(和
子流程
,以及它所构建的POSIXAPI)的全部要点就是管道

那么,你能做些什么呢


在linux上,您可以使用该模块。它也可以在其他*nix平台上工作,但即使它被构建并包含在您的stdlib中,也可能无法工作。正如文件所说:

因为伪终端处理高度依赖于平台,所以只有针对Linux的代码才可以这样做。(Linux代码应该可以在其他平台上运行,但尚未经过测试。)

它肯定在2.7和3.3版本的*BSD平台上运行,文档中的示例似乎在Mac OS X和FreeBSD上都能运行……但这就是我所检查的


同时,大多数POSIX平台至少会有,这并不难,所以这里有一个简单的程序,它播放作为第一个参数传递的歌曲的前5秒:

import os
import pty
import sys
import time

pid, fd = os.forkpty()
if pid:
    time.sleep(5)
    os.write(fd, 'q')
else:
    os.spawnl(os.P_WAIT, # mode
              '/usr/local/bin/mpg123', # path
              '/usr/local/bin/mpg123', '-C', sys.argv[1]) # args

注意,我在上面使用了
os.spawnl
。这可能不是你在真正的程序中想要的;这是出于教学目的,鼓励您阅读文档(以及相应的手册页)并理解这一系列函数

如前所述,这不使用
PATH
环境变量,因此需要指定程序的完整路径。您可以使用
spawnlp
而不是
spawnl
来修复此问题

另外,
spawn