67

I'm trying to write some short script in python which would start another python code in subprocess if is not already started else terminate terminal & app (Linux).

So it looks like:

#!/usr/bin/python
from subprocess import Popen

text_file = open(".proc", "rb")
dat = text_file.read()
text_file.close()

def do(dat):

    text_file = open(".proc", "w")
    p = None

    if dat == "x" :

        p = Popen('python StripCore.py', shell=True)
        text_file.write( str( p.pid ) )

    else :
        text_file.write( "x" )

        p = # Assign process by pid / pid from int( dat )
        p.terminate()

    text_file.close()

do( dat )

Have problem of lacking knowledge to name proces by pid which app reads from file ".proc". The other problem is that interpreter says that string named dat is not equal to "x" ??? What I've missed ?

Alex
  • 3,167
  • 6
  • 35
  • 50
  • 4
    Why are you passing `shell=True`? AFAIK it isn't needed in your use case. Note also that when using `shell=True` the pid returned by `p.pid` is *not* the pid of the python process, but the pid of the shell spawned to execute this process. – Bakuriu Jul 25 '13 at 12:34
  • +1 for your comment, but I consider it as appropriate because I need to close terminal as well. – Alex Jul 25 '13 at 12:38

3 Answers3

153

Using the awesome psutil library it's pretty simple:

p = psutil.Process(pid)
p.terminate()  #or p.kill()

If you don't want to install a new library, you can use the os module:

import os
import signal

os.kill(pid, signal.SIGTERM) #or signal.SIGKILL 

See also the os.kill documentation.


If you are interested in starting the command python StripCore.py if it is not running, and killing it otherwise, you can use psutil to do this reliably.

Something like:

import psutil
from subprocess import Popen

for process in psutil.process_iter():
    if process.cmdline() == ['python', 'StripCore.py']:
        print('Process found. Terminating it.')
        process.terminate()
        break
else:
    print('Process not found: starting it.')
    Popen(['python', 'StripCore.py'])

Sample run:

$python test_strip.py   #test_strip.py contains the code above
Process not found: starting it.
$python test_strip.py 
Process found. Terminating it.
$python test_strip.py 
Process not found: starting it.
$killall python
$python test_strip.py 
Process not found: starting it.
$python test_strip.py 
Process found. Terminating it.
$python test_strip.py 
Process not found: starting it.

Note: In previous psutil versions cmdline was an attribute instead of a method.

0 _
  • 10,524
  • 11
  • 77
  • 109
Bakuriu
  • 98,325
  • 22
  • 197
  • 231
  • Thanks, but the main problem for me is how to get the pid of running application? – Alex Jul 25 '13 at 12:36
  • 5
    @Alex What do you mean? You'd like to terminate the process that is executing? Then simply use `sys.exit()`. If you want to access the `pid` of the current process use `os.getpid()`. – Bakuriu Jul 25 '13 at 12:42
  • at_Bakuriu excuse me please (mi dispiace). I just want to make script which will run some app if it is not started. And if app is started, to terminate this app, and self too. – Alex Jul 25 '13 at 14:24
  • 1
    @Alex I've updated my question with a clean solution using `psutil`. If you want you can achieve this even using only the standard library but it will be less reliable(i.e. you save the pid to a file. A different process kills your `StripCore.py` script and starts a new process that gets assigned to the new pid: how can you know that the same pid now doesn't refer to the script running? This isn't a problem with psutil since you can check the `cmdline` attribute) and more complicated. – Bakuriu Jul 25 '13 at 17:53
  • I think you mean `signal.SIGTERM`, not `signal.SIGQUIT`, sigquit is a keyboard emitted event. – ThorSummoner Aug 30 '15 at 22:37
  • @Bakuriu Thanks for the answer. Do you think this technique will also work on Mac OS-X, and specifically, if I need to "capture" a Mac application (which cannot run as a subprocess of the python-script) in order to terminate it? – Motti Shneor Jun 27 '16 at 09:20
  • @MottiShneor This should work on any OS supported by psutil, which include OS X, Windows, BSD, Solaris etc. – Bakuriu Jun 27 '16 at 09:34
  • @AJP It's not due to the *python* version, but to the version of psutil. `cmdline` was an attribute in previous versions. – Bakuriu Aug 19 '17 at 18:23
4

I wanted to do the same thing as, but I wanted to do it in the one file.

So the logic would be:

  • if a script with my name is running, kill it, then exit
  • if a script with my name is not running, do stuff

I modified the answer by Bakuriu and came up with this:

from os import getpid
from sys import argv, exit
import psutil  ## pip install psutil

myname = argv[0]
mypid = getpid()
for process in psutil.process_iter():
    if process.pid != mypid:
        for path in process.cmdline():
            if myname in path:
                print "process found"
                process.terminate()
                exit()

## your program starts here...

Running the script will do whatever the script does. Running another instance of the script will kill any existing instance of the script.

I use this to display a little PyGTK calendar widget which runs when I click the clock. If I click and the calendar is not up, the calendar displays. If the calendar is running and I click the clock, the calendar disappears.

suprjami
  • 287
  • 1
  • 7
0

So, not directly related but this is the first question that appears when you try to find how to terminate a process running from a specific folder using Python.

It also answers the question in a way(even though it is an old one with lots of answers).

While creating a faster way to scrape some government sites for data I had an issue where if any of the processes in the pool got stuck they would be skipped but still take up memory from my computer. This is the solution I reached for killing them, if anyone knows a better way to do it please let me know!

import pandas as pd
import wmi
from re import escape
import os

def kill_process(kill_path, execs):
    f = wmi.WMI()
    esc = escape(kill_path)
    temp = {'id':[], 'path':[], 'name':[]}
    for process in f.Win32_Process():
        temp['id'].append(process.ProcessId)
        temp['path'].append(process.ExecutablePath)
        temp['name'].append(process.Name)
    temp = pd.DataFrame(temp)
    temp = temp.dropna(subset=['path']).reset_index().drop(columns=['index'])
    temp = temp.loc[temp['path'].str.contains(esc)].loc[temp.name.isin(execs)].reset_index().drop(columns=['index'])
    [os.system('taskkill /PID {} /f'.format(t)) for t in temp['id']]