繁体   English   中英

python 2.7-与mpg123的子进程控件交互

[英]python 2.7 - subprocess control interaction with mpg123

几周前我在这里问了一个与此相关的问题: Python,mpg123和子进程未正确使用stdin.write或进行通讯

多亏了那里的帮助,我才得以完成当时所需的工作。 (没有调用q,而是终止了子进程以将其停止。)##标题##现在,我似乎又陷入了混乱。

    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 what.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 (以及subprocess和它所基于的POSIX API)的重点是管道。

所以你能对它做点啥?


在Linux上,您可以使用pty模块。 它也可以在其他* nix平台上工作,但可能不行,即使它已构建并包含在您的stdlib中。 正如文档所说:

由于伪终端处理高度依赖平台,因此有代码仅在Linux上执行。 (Linux代码应该可以在其他平台上运行,但尚未经过测试。)

它肯定可以在2.7和3.3的* BSD平台上运行,并且文档中的示例似乎可以在Mac OS X和FreeBSD上运行……但是据我所知。


同时,大多数POSIX平台至少会具有os.forkpty ,这并不难,所以这是一个微不足道的程序,它播放一首歌曲的前5秒作为其首个arg传递:

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需要手动exec 如果您知道自己在做什么,则可能要使用execl (或execlp )而不是spawnl

只要小心,您甚至可以在subprocess使用大多数功能(不要创建任何管道,并且请记住,您最终将完成两个 fork ,因此请确保正确设置父/子关系) 。

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

无论如何,您确实确实需要阅读文档以了解这些功能的作用,而不仅仅是将其当作您不了解的魔术代码来对待。 因此,我有意使用了最简单的解决方案来鼓励这一点。


在Windows上,没有pty这样的东西,也没有办法使用Python内置的功能来做到这一点。 您将需要使用各种第三方库之一来控制cmd.exe控制台(又名DOS提示符)。

基于abarnert的想法,我们可以打开一个伪终端并将其传递给子进程。

import os
import pty
import subprocess
import time

master, slave = os.openpty()

p = subprocess.Popen(['mpg123', '-C', 'music.mp3'], stdin=master)
time.sleep(3)
os.write(slave, 's')
time.sleep(3)
os.write(slave, 's')
time.sleep(6)
os.write(slave, 'q')

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM