toto
toto

Reputation: 360

Can't kill robocopy subprocess from python

In my project on windows, I would like to start the mirroring of two directories.

I know that I can use python watchdog to do that, but I though that using robocopy would be easier and faster.

To simplify the situation, let's assume I have a GUI with two buttons: start and stop mirroring.

Here below is a snippet with the relevant code:

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())

When you click on the start button, you get a PID print out on the console and if I check this PID in the tasklist it corresponds to 'cmd.exe' process and the robocopy starts its job.

When you click on stop, the cmd.exe process corresponding to the PID disappers, but the background robocopy continues!!

I have tried several variations, but no luck.

Do you have some advises? Do you know if somebody has found a solution? Or maybe implemented a mirroring watchdog?

thanks

Update

Following the the suggestion of @Ulrich, setting shell=False is actually doing the trick and killing the robocopy process.

Thanks!

Upvotes: 0

Views: 161

Answers (1)

Grismar
Grismar

Reputation: 31354

By changing this:

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

To this:

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

... you're ensuring that the process will be started directly from the current process, without starting a new shell process to start it in.

The PID you were getting back was for the shell process, and you can kill the shell without killing processes launched from that shell. By not starting it in a new shell, the PID you're getting back is the PID of the actual process and you'll be able to kill it as expected.

As the documentation states: "The only time you need to specify shell=True on Windows is when the command you wish to execute is built into the shell (e.g. dir or copy). You do not need shell=True to run a batch file or console-based executable."

Upvotes: 1

Related Questions