[英]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.