在打印process.stdout时,无法杀死Popen创建的Sub进程

时间:2015-01-23 06:59:08

标签: python windows subprocess

我创建了一个脚本,它应该运行一个命令并在15秒后终止它

import logging

import subprocess
import time
import os
import sys
import signal

#cmd = "ping 192.168.1.1 -t"
cmd = "C:\\MyAPP\MyExe.exe -t 80 -I C:\MyApp\Temp -M Documents"

proc=subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,shell=True)

**for line in proc.stdout:
    print (line.decode("utf-8"), end='')**

time.sleep(15)
os.kill(proc.pid, signal.SIGTERM)
#proc.kill() #Tried this too but no luck 

这不会终止我的子流程。但是如果我注释掉登录到stdout部分,即

for line in proc.stdout:
    print (line.decode("utf-8"), end='')

子进程已被杀死。

我也试过proc.kill() and CTRL_C_EVENT但没有运气。 任何帮助将受到高度赞赏。请把我视为python的新手

2 个答案:

答案 0 :(得分:4)

要在逐行打印输出的同时在15秒内终止子进程:

#!/usr/bin/env python
from __future__ import print_function
from threading import Timer
from subprocess import Popen, PIPE, STDOUT

# start process
cmd = r"C:\MyAPP\MyExe.exe -t 80 -I C:\MyApp\Temp -M Documents"
process = Popen(cmd, stdout=PIPE, stderr=STDOUT,
                bufsize=1, universal_newlines=True)

# terminate process in 15 seconds
timer = Timer(15, terminate, args=[process])
timer.start()

# print output
for line in iter(process.stdout.readline, ''):
    print(line, end='')
process.stdout.close()
process.wait() # wait for the child process to finish
timer.cancel()

注意,这里不需要shell=True。您可以将terminate()定义为:

def terminate(process):
    if process.poll() is None:
        try:
            process.terminate()
        except EnvironmentError:
            pass # ignore 

如果要终止整个进程树,请将terminate()定义为:

from subprocess import call

def terminate(process):
    if process.poll() is None:
        call('taskkill /F /T /PID ' + str(process.pid))
  1. 对Windows路径使用原始字符串文字:r""否则应该转义字符串文字中的所有反斜杠
  2. 删除shell=True。它无缘无故地创建了一个额外的过程
  3. universal_newlines=True启用文本模式(在Python 3上使用区域设置首选编码将字节解码为Unicode文本)
  4. iter(process.stdout.readline, '')是与Python 2兼容所必需的(否则由于预读缓冲区错误,数据可能会延迟打印)
  5. 使用process.terminate()代替process.send_signal(signal.SIGTERM)os.kill(proc.pid, signal.SIGTERM)
  6. taskkill允许终止Windows上的进程树

答案 1 :(得分:1)

问题是从stdout读取阻塞。您需要读取子进程的输出或在单独的线程上运行计时器。

from subprocess import Popen, PIPE
from threading import Thread
from time import sleep

class ProcKiller(Thread):
    def __init__(self, proc, time_limit):
        super(ProcKiller, self).__init__()
        self.proc = proc
        self.time_limit = time_limit

    def run(self):
        sleep(self.time_limit)
        self.proc.kill()


p = Popen('while true; do echo hi; sleep 1; done', shell=True)
t = ProcKiller(p, 5)
t.start()
p.communicate()

已编辑以反映评论中的建议更改

from subprocess import Popen, PIPE
from threading import Thread
from time import sleep
from signal import SIGTERM
import os

class ProcKiller(Thread):
    def __init__(self, proc, time_limit):
        super(ProcKiller, self).__init__()
        self.proc = proc
        self.time_limit = time_limit

    def run(self):
        sleep(self.time_limit)
        os.kill(self.proc.pid, SIGTERM)

p = Popen('while true; do echo hi; sleep 1; done', shell=True)
t = ProcKiller(p, 5)
t.start()
p.communicate()