1

サブプロセスを使用してシステムコマンドを実行し、出力を読み取ろうとしています。

しかし、コマンドに 10 秒以上かかる場合は、サブプロセスを強制終了したいと考えています。

これをいくつかの方法で試しました。

私の最後の試みは、この投稿に触発されました: https://stackoverflow.com/a/3326559/969208

例:

import os
import signal
from subprocess import Popen, PIPE

class Alarm(Exception):
    pass

def alarm_handler(signum, frame):
    raise Alarm

def pexec(args):

    p = Popen(args, stdout=PIPE, stderr=PIPE)

    signal.signal(signal.SIGALRM, alarm_handler)
    signal.alarm(10)

    stdout = stderr = ''
    try:
        stdout, stderr = p.communicate()
        signal.alarm(0)
    except Alarm:
        try:
            os.kill(p.pid, signal.SIGKILL)
        except:
            pass

    return (stdout, stderr)

問題は次のとおりです。プログラムが終了した後、return キーを押すまで cli に文字が表示されません。また、改行を押しても改行されません。

これは stdout および stderr パイプと関係があると思います。

パイプからのフラッシュと読み取りを試みました(p.stdout.flush())

また、さまざまな Popen 引数を試してみましたが、何かを見落としている可能性があります。ここはシンプルにしようと思いました。

これを Debian サーバーで実行しています。

ここで何か不足していますか?

編集:

これは、進行中の ffmpeg プロセスを強制終了する場合にのみ発生するようです。10秒前にffmpegのプロセスが正常終了すれば、何の問題もありません。

出力を印刷するコマンド、印刷しないコマンド、ファイルの整合性をチェックする ffmpeg コマンドなど、10 秒以上かかるいくつかの異なるコマンドを実行してみました。

args = ['sleep', '12s'] # Works fine
args = ['ls', '-R', '/var'] # Works fine, prints lots for a long time
args = ['ffmpeg', '-v', '1', '-i', 'large_file.mov','-f', 'null', '-'] # Breaks cli output

ffmpeg は \r を使用して印刷し、すべてを strerr パイプに印刷すると思います。これが原因でしょうか?それを修正する方法はありますか?

4

3 に答える 3

1

良い。あなたのコードは、私のUbuntuサーバーで確実に正常に動作します。

(これは Debian のいとこか兄弟だと思います)

コードをテストできるように、さらに数行追加しました。

import os
import signal
from subprocess import Popen, PIPE

class Alarm(Exception):
    pass

def alarm_handler(signum, frame):
    raise Alarm
def pexec(args):
    p = Popen(args, stdout=PIPE, stderr=PIPE)

    signal.signal(signal.SIGALRM, alarm_handler)
    signal.alarm(1)

    stderr = ''
    try:
        stdout, stderr = p.communicate()
        signal.alarm(0)
    except Alarm:
    print "Done!"
        try:
            os.kill(p.pid, signal.SIGKILL)
        except:
            pass

    return (stdout, stderr)

args = ('find', '/', '-name','*')
stdout = pexec(args)
print "----------------------result--------------------------"
print stdout
print "----------------------result--------------------------"

魅力のように機能します。

このコードがサーバーで機能する場合、実際には問題があると思います

データを取得しようとしているコマンド ライン アプリケーション。

于 2012-05-14T15:33:57.397 に答える
0

私も同じ問題を抱えてる。実行中の FFmpeg を Python サブプロセスから正常に終了させることができないため、<process>.kill(). ただし、これはFFmpegがttyのモードを適切に復元しないことを意味すると思います(ここで説明されているように: https://askubuntu.com/a/172747 )

bash プロンプトで実行することでシェルを元に戻すことができますresetが、それによって画面がクリアされるため、作業を続けてもスクリプトの出力を確認できません。

実行するstty echoと、シェル セッションのエコーがオンになります。

FFmpeg を削除した後で、スクリプトでこれを実行することもできます。私がやっている:

ffmpeg_popen.kill()
ffmpeg_popen.wait()
subprocess.call(["stty", "echo"])

これは、シェルとしてbashを使用するUbuntuで機能します。YMMVですが、お役に立てば幸いです。ハッキーなにおいがしますが、これが私が見つけた最良の解決策です。

于 2016-03-17T21:55:28.880 に答える
0

私はffmpegで同様の問題に遭遇しました。Popen.kill() を使用して ffmpeg が強制終了された場合、適切に閉じられず、端末でエコーが回復しないようです。

stdin へのパイプを使用してこれを解決し、cli セッションで行うように q を記述して ffmpeg を閉じます。

p = Popen(args, stdin=PIPE stdout=PIPE, stderr=PIPE)
p.stdin.write(b"q")

デッドロックを回避するには、おそらく Popen.communicate を使用することをお勧めします。以下も機能します。

p = Popen(args, stdin=PIPE stdout=PIPE, stderr=PIPE)
p.communicate(b'q')

しかし、次のようにも機能するようです:

p = Popen(args, stdin=PIPE stdout=PIPE, stderr=PIPE)
p.kill()

入力パイプがある場合、このffmpegがきれいに閉じる原因はわかりません。おそらく、そもそもこのバグの原因と関係があるのでしょうか?

于 2017-09-27T00:44:45.123 に答える