如何终止使用shell=True启动的python子进程
我正在使用以下命令启动子流程:如何终止使用shell=True启动的python子进程,python,linux,subprocess,kill-process,Python,Linux,Subprocess,Kill Process,我正在使用以下命令启动子流程: p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) 但是,当我尝试使用以下方法杀人时: p.terminate() 或 该命令一直在后台运行,因此我想知道如何实际终止该进程 请注意,当我使用以下命令运行命令时: p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) 当发出p.terminate()时,它会成功终止shell=T
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
但是,当我尝试使用以下方法杀人时:
p.terminate()
或
该命令一直在后台运行,因此我想知道如何实际终止该进程
请注意,当我使用以下命令运行命令时:
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
当发出
p.terminate()
时,它会成功终止shell=True
shell是子进程,命令是它的子进程。因此,任何SIGTERM
或SIGKILL
都会杀死shell,但不会杀死它的子进程,我不记得有什么好的方法。
我能想到的最好的方法是使用
shell=False
,否则,当您杀死父shell进程时,它将留下一个失效的shell进程。正如Sai所说,shell就是子shell,所以信号被它截获——我发现的最好的方法是使用shell=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()应该按照您的预期工作。使用a以便能够向组中的所有进程发送信号。为此,您应该将附加到派生/子进程的父进程,在您的示例中,它是一个shell。这将使其成为流程的组长。现在,当一个信号被发送到进程组负责人时,它被传输到这个组的所有子进程
代码如下:
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.kill()
我找到了一个方便的解决方法:
p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)
这将导致cmd继承shell进程,而不是让shell启动一个子进程,子进程不会被终止p.pid
将是cmd进程的id
p.kill()
应该可以工作
我不知道这会对你的管道产生什么影响。我可以用
from subprocess import Popen
process = Popen(command, shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))
它杀死了cmd.exe
和我发出命令的程序
(在Windows上)如果您可以使用,则此功能非常有效:
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)
没有一个答案对我有效,所以我留下了有效的代码。在我的例子中,即使在使用.kill()
终止进程并获得.poll()
返回代码后,进程也没有终止
遵循子流程.Popen
:
“…为了正确清理,行为良好的应用程序应该终止子进程并完成通信…”
在我的例子中,调用proc.kill()
后,我丢失了proc.communicate()
。这将清理进程stdin、stdout。。。我知道这是一个老问题,但这可能有助于寻找其他方法。这就是我在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 os
import signal
import subprocess
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
os.killpg(os.getpgid(pro.pid), signal.SIGINT)
这不会杀死你所有的任务,但是p.pid的进程我没有看到这里提到的,所以我把它放在那里,以防有人需要它。如果您只想确保子流程成功终止,那么可以将其放在上下文管理器中。例如,我希望我的标准打印机打印一个输出图像,并使用上下文管理器确保子进程终止
导入子流程
将open(filename,'rb')作为f:
img=f.read()
将subprocess.Popen(“/usr/bin/lpr”,stdin=subprocess.PIPE)作为lpr:
lpr.stdin.write(img)
打印('打印图像…')
我相信这种方法也是跨平台的。对于Python 3.5
或+(实际上是在Python 3.8
上测试的)有一种非常简单的方法
然后,如果你有键盘输入检测或类似的东西,你的代码可能会在某个时候崩溃。在这种情况下,在给出错误的代码/函数行中,只需使用:
try:
FailingCode #here goes the code which is raising KeyboardInterrupt
except KeyboardInterrupt:
pass
这段代码所做的只是向正在运行的进程发送一个“CTRL+C”信号,这将导致进程被终止。这在Pyhton 3.8.10 Win 10上对我有效
我尝试了子进程。Popenshell true:
subprocess.Popen.kill
subprocess.Popen.terminate
但这是真的
不要使用os.kill()
这是你如何使用它的:
from ExecutableProgram import ExecutableProgram
program = ExecutableProgram(r"<your executable>")
program.startProgram()
input()
program.stopProgram()
从可执行程序导入可执行程序
程序=可执行程序(r“”)
program.startProgram()
输入()
program.stopProgram()
在我的例子中,由于cmd是“cd path&&zsync etc”,所以它并没有真正的帮助。因此,这实际上使命令失败!使用绝对路径而不是更改目录。。。(可选)将os.chdir(…)添加到该目录中…内置了更改子进程工作目录的功能。只需将cwd
参数传递给即可。我使用了shlex,但问题仍然存在,kill并不是终止子进程。subprocess.CREATE_NEW_PROCESS_GROUP
与此有何关系?我们的测试建议设置ID!=setpgid,并且该os.pgkill仅终止仍具有相同进程组id的子进程。已更改进程组的进程不会终止,即使它们可能仍具有相同的会话id。@PiotrDobrogost:我不建议执行os.setpid(),因为它还有其他影响。其中,它断开了控制TTY的连接,使新流程成为流程组长。看看在Windows中如何执行此操作setsid
仅在*nix系统上可用。您的cmd
看起来像什么?它可能包含一个命令,该命令触发要启动的多个进程。因此,不清楚您谈论的是哪个进程。相关:没有shell=True
会有很大的区别吗?AttributeError:“进程”对象没有att
import os
import signal
import subprocess
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
os.killpg(os.getpgid(pro.pid), signal.SIGINT)
import subprocess, signal, time
p = subprocess.Popen(['cmd'], shell=True)
time.sleep(5) #Wait 5 secs before killing
p.send_signal(signal.CTRL_C_EVENT)
try:
FailingCode #here goes the code which is raising KeyboardInterrupt
except KeyboardInterrupt:
pass
import subprocess
class ExecutableProgram:
program = None
def __init__(self,path):
self.path = path
def startProgram(self):
self.program = subprocess.Popen(self.path)
def stopProgram(self):
self.program.kill()
from ExecutableProgram import ExecutableProgram
program = ExecutableProgram(r"<your executable>")
program.startProgram()
input()
program.stopProgram()