シェルで起動したPythonサブプロセスを終了する方法= true
-
24-10-2019 - |
質問
次のコマンドでサブプロセスを起動しています。
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
しかし、私が使用して殺そうとするとき:
p.terminate()
また
p.kill()
コマンドはバックグラウンドで実行され続けているので、実際にプロセスを実際に終了する方法を疑問に思っていました。
コマンドを実行したとき:
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
発行時に正常に終了します p.terminate()
.
解決
使う プロセスグループ グループ内のすべてのプロセスに信号を送信できるように。そのためには、aを添付する必要があります セッションID あなたの場合のシェルである産卵/子プロセスの親プロセスに。これにより、プロセスのグループリーダーになります。そのため、信号がプロセスグループリーダーに送信されると、このグループのすべての子プロセスに送信されます。
これがコードです:
import os
import signal
import subprocess
# The os.setsid() is passed in the argument preexec_fn so
# it's run after the fork() and before exec() to run the shell.
pro = subprocess.Popen(cmd, stdout=subprocess.PIPE,
shell=True, preexec_fn=os.setsid)
os.killpg(os.getpgid(pro.pid), signal.SIGTERM) # Send the signal to all the process groups
他のヒント
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
p.kill()
p.kill()
シェルプロセスを殺すことになります cmd
まだ実行されています。
私はこれを次のように修正する便利な修正を見つけました:
p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)
これにより、CMDはシェルに子プロセスを起動するのではなく、シェルプロセスを継承しますが、これは殺されません。 p.pid
CMDプロセスのIDになります。
p.kill()
動作するはずです。
しかし、これがあなたのパイプにどのような影響を与えるかはわかりません。
使用できる場合 プシュタル, 、その後、これは完全に機能します:
import subprocess
import psutil
def kill(proc_pid):
process = psutil.Process(proc_pid)
for proc in process.children(recursive=True):
proc.kill()
process.kill()
proc = subprocess.Popen(["infinite_app", "param"], shell=True)
try:
proc.wait(timeout=3)
except subprocess.TimeoutExpired:
kill(proc.pid)
私はそれを使ってそれをすることができました
from subprocess import Popen
process = Popen(command, shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))
それは殺した cmd.exe
そして、私がコマンドを与えたプログラム。
(Windowsで)
いつ shell=True
シェルは子のプロセスであり、コマンドはその子供です。だから任意 SIGTERM
また SIGKILL
シェルを殺しますが、子どものプロセスではなく、私はそれを行う良い方法を覚えていません。私が考えることができる最善の方法は使用することです shell=False
, それ以外の場合は、親のシェルプロセスを殺すと、無効なシェルプロセスが残ります。
この回答のいずれも私のために機能しなかったので、機能したコードを離れています。私の場合でも、プロセスを殺した後でも .kill()
そして、取得します .poll()
プロセスが終了しなかったコードを返します。
続いて subprocess.Popen
ドキュメンテーション:
「...適切にクリーンアップするために、行儀の良いアプリケーションは子どものプロセスを殺し、コミュニケーションを終了する必要があります...」
proc = subprocess.Popen(...)
try:
outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
私の場合、私はそれを逃していました proc.communicate()
電話後 proc.kill()
. 。これにより、プロセスがstdin、stdout ...をクリーニングし、プロセスを終了します。
サイが言ったように、シェルは子供なので、信号はそれによって傍受されます - 私が見つけた最善の方法は、シェル= falseを使用し、shlexを使用してコマンドラインを分割することです。
if isinstance(command, unicode):
cmd = command.encode('utf8')
args = shlex.split(cmd)
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
次に、p.kill()とp.terminate()は、期待する方法を機能させる必要があります。
私が使用できると思うもの:
import os
import signal
import subprocess
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
os.killpg(os.getpgid(pro.pid), signal.SIGINT)
これはあなたのすべてのタスクを殺すのではなく、p.pidでのプロセスを殺します
私はこれが古い質問であることを知っていますが、これは誰かが別の方法を探しているのに役立つかもしれません。これは、私が呼んだプロセスを殺すためにWindowsで使用するものです。
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.call(["taskkill", "/IM", "robocopy.exe", "/T", "/F"], startupinfo=si)
/imは画像名です。必要に応じて /pidすることもできます。 /tプロセスと子プロセスを殺します。 /f力はそれを終了します。 Siは、私が設定しているように、CMDウィンドウを表示せずにこれを行う方法です。このコードはPython 3で使用されます。
グループ内のすべてのプロセスに信号を送信します
self.proc = Popen(commands,
stdout=PIPE,
stderr=STDOUT,
universal_newlines=True,
preexec_fn=os.setsid)
os.killpg(os.getpgid(self.proc.pid), signal.SIGHUP)
os.killpg(os.getpgid(self.proc.pid), signal.SIGTERM)
ここで言及されているのを見たことがないので、誰かがそれを必要としている場合に備えて出しています。あなたがしたいのは、あなたのサブプロセスが正常に終了することを確認することだけなら、それをコンテキストマネージャーに入れることができます。たとえば、標準のプリンターにアウトイメージを印刷することを望み、コンテキストマネージャーを使用してサブプロセスが終了するようにしました。
import subprocess
with open(filename,'rb') as f:
img=f.read()
with subprocess.Popen("/usr/bin/lpr", stdin=subprocess.PIPE) as lpr:
lpr.stdin.write(img)
print('Printed image...')
この方法はクロスプラットフォームでもあると思います。