提问人:user175259 提问时间:1/25/2011 最后编辑:Piotr Dobrogostuser175259 更新时间:5/23/2022 访问量:491532
如何终止使用 shell=True 启动的 python 子进程
How to terminate a python subprocess launched with shell=True
问:
我正在使用以下命令启动一个子进程:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
但是,当我尝试使用以下方法杀死时:
p.terminate()
或
p.kill()
该命令一直在后台运行,所以我想知道如何才能真正终止该过程。
请注意,当我使用以下命令运行命令时:
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
在发出 时,它确实成功终止。p.terminate()
答:
当 shell 是子进程,命令是其子进程时。因此,任何 or 都会杀死 shell,但不会杀死它的子进程,我不记得有什么好方法可以做到这一点。
我能想到的最好的方法是使用 ,否则当你杀死父 shell 进程时,它会留下一个失效的 shell 进程。shell=True
SIGTERM
SIGKILL
shell=False
评论
正如 Sai 所说,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() 应该按照您的预期工作。
评论
使用进程组,以便能够向组中的所有进程发送信号。为此,您应该将会话 ID 附加到生成/子进程的父进程,在您的情况下,这是一个 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
评论
subprocess.CREATE_NEW_PROCESS_GROUP
CREATE_NEW_PROCESS_GROUP
可用于在 Windows 上模拟 start_new_session=True
setsid
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
p.kill()
p.kill()
最终终止 shell 进程并且仍在运行。cmd
我通过以下方式找到了一个方便的解决方法:
p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)
这将导致 cmd 继承 shell 进程,而不是让 shell 启动子进程,该子进程不会被终止。 将是您的 cmd 进程的 ID。p.pid
p.kill()
应该工作。
我不知道这会对你的管道产生什么影响。
评论
我可以用
from subprocess import Popen
process = Popen(command, shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))
它杀死了我发出命令的程序。cmd.exe
(在 Windows 上)
评论
Popen("TASKKILL /F /IM " + process_name)
command
如果您可以使用 psutil,那么这可以完美地工作:
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)
评论
AttributeError: 'Process' object has no attribute 'get_children
为。pip install psutil
这些答案都不适合我,所以我留下了有效的代码。就我而言,即使在终止进程并获取返回代码后,该进程也没有终止。.kill()
.poll()
按照文档:subprocess.Popen
"...为了正确清理,一个行为良好的应用程序应该杀死子进程并完成通信......”
proc = subprocess.Popen(...)
try:
outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
就我而言,我错过了电话后。这清理了过程 stdin、stdout ...并终止该进程。proc.communicate()
proc.kill()
评论
将信号发送到组中的所有进程
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)
有一种非常简单的方法可以用于 or +(实际上在Python 3.5
Python 3.8
)
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
这段代码所做的只是向正在运行的进程发送一个“+”信号,这将导致进程被终止。CTRLC
评论
signal
对我有用的解决方案
if os.name == 'nt': # windows
subprocess.Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))
else:
os.kill(process.pid, signal.SIGTERM)
完整的解决方案,将在达到超时或通过回调函数的特定条件时终止正在运行的进程(包括子树)。 在撰写本文时,从 Python 2.7 到 3.10 都可以在 Windows 和 Linux 上运行。
安装方式pip install command_runner
超时示例:
from command_runner import command_runner
# Kills ping after 2 seconds
exit_code, output = command_runner('ping 127.0.0.1', shell=True, timeout=2)
具体情况示例: 如果当前系统时间秒数字> 5,我们将停止 ping
from time import time
from command_runner import command_runner
def my_condition():
# Arbitrary condition for demo
return True if int(str(int(time()))[-1]) > 5
# Calls my_condition() every second (check_interval) and kills ping if my_condition() returns True
exit_code, output = command_runner('ping 127.0.0.1', shell=True, stop_on=my_condition, check_interval=1)
评论
cmd
shell=True