1

ここで数週間前にこれに関連する質問をしました: Python、mpg123、およびサブプロセスがstdin.writeまたはcommunicationを適切に使用していません

そこからの助けのおかげで、私はその時に必要なことをすることができました. (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 の標準的なコントロールと同じように mpg123 を終了するには、これが必要です (「q」を押して終了するか、「-」を押して音量を下げるか、「+」を押して音量を上げるなど)。 )、今私は上記のコードを使用しています。これは理論的には機能するはずであり、同様のプログラムで機能します。サブプロセスを使用して、mpg123 に組み込まれているコントロール (「mpg123 -C what.mp3」を使用してアクセスできるコントロール) を使用する方法を知っている人はいますか? コントロールが必要になるので、terminate ではもう十分ではありません ^_^

編集: 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')
4

2 に答える 2

1

コントロールが本当に必要な場合は、単に使用することはできませんPopen

mpg123stdin がファイルまたはパイプの場合ではなく、tty の場合にのみ端末制御を有効にします。そのため、バナーに次の行が表示されます。

Terminal control enabled, press 'h' for listing of keys and functions.

そして、Popen(およびsubprocess、およびそれが構築されている POSIX API) の要点はパイプです。

それで、あなたはそれについて何ができますか?


ptyLinux では、モジュールを使用できます。他の *nix プラットフォームでも動作する可能性がありますが、ビルドされて stdlib に含まれていても動作しない場合があります。ドキュメントが言うように:

疑似端末の処理はプラットフォームに大きく依存するため、Linux 専用のコードがあります。(Linux コードは他のプラットフォームでも動作するはずですが、まだテストされていません。)

2.7 と 3.3 の *BSD プラットフォームで確実に動作し、ドキュメントの例は Mac OS X と FreeBSD の両方で動作するようですが、私が確認した限りでは.


一方、ほとんどの POSIX プラットフォームには少なくともos.forkpty.

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(または) を使用することをお勧めします。execlpspawnl

注意さえすれば、ほとんどの機能を使用することもできsubprocessます (パイプを作成しないでください。2 つ forkの s を実行することになるので、親子関係を適切に設定してください)。

mpg123 また、パスを に2 回渡す必要があることにも注意してください。1 回はパスとして、次に 1 回は子プログラムのargv[0]. 2回目で合格することもできますmpg123。または、理想的にpsは、シェルから実行したときに何が表示されるかを見て、それを渡します。いずれにせよ、何かargv[0];として渡す必要があります。つまり、 mpg123-Cは、コントロール キーを有効にargv[0]するフラグを指定したとは見なさず、名前を に変更してフラグなしで実行したとは見なしません…</p> -C-C

とにかく、理解できない魔法のコードのように扱うのではなく、これらの関数のそれぞれが何をするのかを理解するために、ドキュメントを読む必要があります。そのため、意図的に最も単純な解決策を使用して、それを促進しました。


Windows では、 のようなものはなく、ptyPython に組み込まれている機能を使用してこれを行う方法はまったくありません。代わりに、cmd.exe コンソール (別名 DOS プロンプト) を制御するために、さまざまなサードパーティ ライブラリのいずれかを使用する必要があります。

于 2013-07-02T01:50:42.830 に答える
1

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')
于 2018-03-28T02:23:28.033 に答える