无法从 python 中终止 robocopy 子进程

Can't kill robocopy subprocess from python

在我的windows项目中,我想启动两个目录的镜像。

我知道我可以使用 python watchdog 来做到这一点,但我认为使用 robocopy 会更容易和更快。

为简化情况,假设我有一个带有两个按钮的 GUI:启动和停止镜像。

下面是带有相关代码的片段:

class MirrorDemon(Thread):
    
    def __init__(self, src, dest) :
        self.threading_flag = Event()
        self.src = src
        self.dest = dest
        self.opt = ' /MIR /MON:1 /MOT:1'
        self.mirror = None
        Thread.__init__(self)
        
        
    def run(self):
        
        command = 'robocopy {} {} {}'.format(str(self.src),str(self.dest), self.opt)
        
        self.p = subprocess.Popen(command.split(), shell=True)
        print(command)
        print('start robocopy with PID {}'.format(self.p.pid))

class Window(QMainWindow, Ui_MainWindow):
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        
    def stop_demon(self):
        self.mirror.threading_flag.set()
        self.mirror.p.kill()      
        self.mirror.join()
        print('stop demon')
    
    def start_demon(self):
        self.mirror = MirrorDemon(Path('./src'), Path('./dest'))
        self.mirror.setDaemon(True)
        self.mirror.start()
        print('start demon')

if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec())

当您单击开始按钮时,您会在控制台上打印出 PID,如果我在任务列表中检查此 PID,它对应于 'cmd.exe' 进程并且 robocopy 开始其工作。

点击停止后,PID对应的cmd.exe进程消失,但后台robocopy仍在继续!!

我尝试了几种变体,但没有成功。

你有什么建议吗?您知道是否有人找到了解决方案吗?或者可能实现了镜像看门狗?

谢谢

更新

按照@Ulrich 的建议,设置 shell=False 实际上是在做这个把戏并杀死 robocopy 进程。

谢谢!

通过改变这个:

self.p = subprocess.Popen(command.split(), shell=True)

为此:

self.p = subprocess.Popen(command.split(), shell=False)

...您确保该进程将直接从当前进程启动,而不启动新的 shell 进程来启动它。

您返回的 PID 是针对 shell 进程的,您可以终止 shell 而无需终止从 shell 启动的进程。通过不在新的 shell 中启动它,您返回的 PID 是实际进程的 PID,您将能够按预期终止它。

the documentation 所述:“您唯一需要在 Windows 上指定 shell=True 的时间是当您希望执行的命令内置于 shell 时(例如目录或副本)。您不需要 shell=True 到 运行 批处理文件或 console-based 可执行文件。"