无法从 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 可执行文件。"
在我的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 可执行文件。"