2013-07-02 329 views
1

子进程控制的交互我问与此相关的几个星期前就在这里一个问题: Python, mpg123 and subprocess not properly using stdin.write or communicate蟒蛇2.7 - 与mpg123的

多亏从那里我能够做什么,我需要的时候提供帮助。 (没有打电话给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 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') 
+0

是否有理由想要控制'mpg123'播放器,而不是使用Python库(或者甚至绑定'libmpg123')来播放音乐并执行自己的控制? – abarnert

+0

主要是因为我是一个新手哈哈,我看到的与Raspberry Pi(我的特定平台)播放的大部分东西都使用mpg123或mpg321,当我说我希望能够播放mp3通过python使用一个子进程与其中一个球员 – codingNewb

+0

首先,对不起我的过度缩写;它似乎导致你误入歧途。每当我处理POSIX风格的代码时,我都会回复使用像'pid'和'fd'这样的单词,好像每个人都应该理解它们的意思。 'pid'是一个进程ID,而不是父ID,在这种情况下,它是_child_进程ID,因此调用它'parentID'会令人困惑。而'fd'是一个文件描述符(或者,对于真正的老年人文件描述符索引),而不是文件目录。 – abarnert

回答

1

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

mpg123只启用终端控制,如果它的标准输入是一个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秒一个简单的程序:

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。这大概是而不是你想要的是一个真正的程序;这是出于教学目的,鼓励你阅读文档(和相应的手册)并理解这一系列功能。

由于the docs的解释,这并不使用PATH环境变量,因此您需要指定程序的完整路径。您可以使用spawnlp而不是spawnl来解决此问题。

此外,spawn可能(事实上,总是这样做,虽然文档不完全清楚)做另一个叉子来执行孩子。这确实没有必要,但spawn会执行您需要手动执行的操作,如果您只需拨打exec即可。如果您知道自己在做什么,则可能需要使用execl(或execlp)而不是spawnl

你甚至可以使用大多数的subprocess的功能,只要你小心(不产生任何管道,并记住,你最终会做2个fork S,所以一定要设立父母/子女关系)。

还要注意的是,你需要的路径传递到mpg123两次 -once作为路径,然后一旦为孩子计划的argv[0]。你也可以第二次通过mpg123。或者,理想情况下,看看当你从shell运行它时所说的ps,并通过它。无论如何,你必须通过作为argv[0];否则,-C结束是在argv[0],这意味着mpg123的不会认为你给了它一个-C标志,使控制键,但不是你把它改名为-C和没有标志跑了......

不管怎样,你真的确实需要阅读文档来理解这些函数的作用,而不是仅仅把它看作你不了解的魔法代码。所以,我故意用最简单的解决方案来鼓励。


在Windows上,有没有这样的事,作为一个pty,没办法带内置到Python的工具来做到这一点的。您需要使用各种第三方库之一来控制cmd.exe控制台(又名DOS提示符)。

+0

这看起来很有前途;谢谢^ _ ^不幸的是它是全新的因此我必须去阅读文档,看看我能不能找到教程^ _^ – codingNewb

+1

我无法得到示例代码开始工作,虽然稍作修改,但...而不是'/ usr/local/bin/mpg123',它位于'/ usr/bin/mpg123'中。有时间修补,再次感谢你^ _^ – codingNewb

+0

@newbToPython:我假设你知道你安装了'mpg123'的地方。但是这提出了一个很好的观点:使用'subprocess'你不必担心'PATH';使用'os.spawn *'变体,你必须阅读文档并思考它。让我更新答案来解释。 – abarnert