2

プロセスが異常終了するか、まったく終了しない場合でも、その時点までに生成された可能性のある出力を収集できるようにしたいと考えています。

このコード例の明白な解決策は、os.kill で子プロセスを強制終了することですが、私の実際のコードでは、子プロセスは NFS を待ってハングし、SIGKILL に応答しません。

#!/usr/bin/python
import subprocess
import os
import time
import signal
import sys
child_script = """
#!/bin/bash
i=0
while [ 1 ]; do
    echo "output line $i"
    i=$(expr $i \+ 1)
    sleep 1
done
"""
childFile = open("/tmp/childProc.sh", 'w')
childFile.write(child_script)
childFile.close()

cmd = ["bash", "/tmp/childProc.sh"]
finish = time.time() + 3
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
while p.poll() is None:
    time.sleep(0.05)
    if finish < time.time():
        print "timed out and killed child, collecting what output exists so far"
        out, err = p.communicate()
        print "got it"
        sys.exit(0)

この場合、タイムアウトに関する print ステートメントが表示され、python スクリプトは終了または進行しません。これを別の方法で実行し、子プロセスから出力を取得する方法を知っている人はいますか

4

4 に答える 4

1

問題は、ターミナルに接続されていない場合、bash が CTRL-C に応答しないことです。SIGHUP または SIGTERM に切り替えるとうまくいくようです:

cmd = ["bash", 'childProc.sh']
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, 
                          stderr=subprocess.STDOUT, 
                          close_fds=True)
time.sleep(3)
print 'killing pid', p.pid
os.kill(p.pid, signal.SIGTERM)
print "timed out and killed child, collecting what output exists so far"
out  = p.communicate()[0]
print "got it", out

出力:

killing pid 5844
timed out and killed child, collecting what output exists so far
got it output line 0
output line 1
output line 2
于 2010-01-28T01:33:02.087 に答える
1

一時ファイルなしでそれを行うPOSIXの方法を次に示します。ここではサブプロセスが少し余分であることを認識していますが、元の質問で使用されているため...

import subprocess
import os
import time
import signal
import sys

pr, pw = os.pipe()
pid = os.fork () 

if pid: #parent
    os.close(pw)
    cmd = ["bash"]
    finish = time.time() + 3
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=pr, close_fds=True)
    while p.poll() is None:
        time.sleep(0.05)
        if finish < time.time():
            os.kill(p.pid, signal.SIGTERM)
            print "timed out and killed child, collecting what output exists so far"
            out, err = p.communicate()
            print "got it: ", out
            sys.exit(0)

else: #child
    os.close(pr)
    child_script = """
    #!/bin/bash
    while [ 1 ]; do
        ((++i))
        echo "output line $i"
        sleep 1
    done
    """
    os.write(pw, child_script)
于 2010-02-11T18:51:43.843 に答える
0

別のstackoverflowの質問には、良いヒントがあります。サブプロセスから「リアルタイム」の情報を取得するにはどうすればよいですか。Python(2.5)のPopen

後者はプロセスの最後にのみ戻るため、そこにあるヒントのほとんどはpipe.readline()代わりに機能します。pipe.communicate()

于 2010-01-28T02:58:11.310 に答える
0

私はまったく同じ問題を抱えていました。subprocess.Popen(または.call)を呼び出すときに次のパラメーターを設定するだけで、(Googleを精査し、関連する多くの問題を見つけた後)問題を修正しました。

stdout=None

stderr=None

これらの関数には多くの問題がありますが、私の特定のケースでは、stdout呼び出していたプロセスによっていっぱいになり、ブロック状態になったと思います。これらをNone(のようなものとは反対にsubprocess.PIPE)に設定することで、これを回避できると思います。

これが誰かに役立つことを願っています。

于 2010-05-08T16:26:27.513 に答える