Consider:
import subprocess
import time
def run_instance():
command = "sleep 30 >out 2>err &"
subprocess.check_output(command, shell=True, start_new_session=True)
def kill_instance():
print(subprocess.check_output(f"pgrep -f 30", shell=True))
subprocess.check_output(f"pkill -f 30", shell=True)
run_instance()
time.sleep(1)
kill_instance()
The output (run under Ubuntu
) is:
b'17483n17484n'
Traceback (most recent call last):
File "test.py", line 15, in <module>
kill_instance()
File "test.py", line 10, in kill_instance
subprocess.check_output(f"pkill -f 30", shell=True)
File "/usr/lib/python3.8/subprocess.py", line 411, in check_output
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
File "/usr/lib/python3.8/subprocess.py", line 512, in run
raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command 'pkill -f 30' died with <Signals.SIGTERM: 15>.
Why does pkill
fail even though pgrep
finds the process?
2
Answers
Common way
The most clean, IMO, way here is to just manage your instance within python (note you don’t even need
shell=True
):Your code
Disclaimer: you shouldn’t be doing this in production.
You are killing your
pkill
. Here’s the same with more verbose output:This outputs on my machine:
(ignore
docker
andfirefox
processes here, they’re just for completeness here and to demonstrate that you’re killing too much processes, ff tabs crash after this)The interesting output part from
pgrep
here:When you call
pkill
, it is a process. It will be there instead ofpgrep
, something like… and you
pkill
all matching processes. So you can kill the running instance successfully, but then kill yourself.To demonstrate that, the following succeeds:
Output:
Sorry for that ugly pipe, maybe there is a simpler way, but Linux
pgrep
cannot exclude self (as opposed to FreeBSD, discussed here). This pipe lists processes, excludespgrep
itself ($$
refers to current parent shell, which is that runspgrep
here) and passes them tokill
.You are vastly overcomplicating things by basically running shell scripts on top of Python.
Here’s (something like) the proper solution.
A more complete example would
proc.wait()
if thekill
failed for whatever reason.