70

I am trying to create a python script which I will later run as a service. Now I want to run a particular part of the code only when iTunes is running. I understand from some research that polling the entire command list and then searching for the application for that list is expensive.

I found out that processes on UNIX-based operating systems create a lock file to notify that a program is currently running, at which point we can use os.stat(location_of_file) to check if the file exists to determine if a program is running or not.

Is there a similar lock file created on Windows?

If not what are the various ways in Python by which we can determine if a process is running or not?

I am using python 2.7 and iTunes COM interface.

martineau
  • 119,623
  • 25
  • 170
  • 301
nightf0x
  • 1,969
  • 3
  • 17
  • 24
  • What does the COM interface do if iTunes isn't running? – Gabe Oct 16 '11 at 20:37
  • If make an object using the COM interface in python, the COM interface automatically opens up iTunes. – nightf0x Oct 16 '11 at 20:39
  • 2
    For what it's worth, it's up to an individual program whether or not it wants to create a lock file or PID file. Not all Linux/UNIX programs do. – David Z Oct 16 '11 at 21:24

21 Answers21

103

You can not rely on lock files in Linux or Windows. I would just bite the bullet and iterate through all the running programs. I really do not believe it will be as "expensive" as you think. psutil is an excellent cross-platform python module cable of enumerating all the running programs on a system.

import psutil    
"someProgram" in (p.name() for p in psutil.process_iter())
monk-time
  • 2,123
  • 1
  • 14
  • 17
Mark
  • 106,305
  • 20
  • 172
  • 230
  • 1
    Upon trying out this program, access is denied for some processes even when I run it as an administrator. I will probably just use try and except to ignore these instances, but it is something to watch out for – trevorKirkby Dec 20 '13 at 01:48
  • 7
    Appears to be BSD now – Anthony Aug 19 '14 at 16:41
  • 1
    Warning: this causes a `psutil.NoSuchProcess` exception if a process that `psutil.get_pid_list()` returned has already exited when `psutil.Process(i).name` is executed. Be sure to catch this. – fnkr Jun 12 '15 at 12:58
  • 1
    Beware of the case. The result is case sensitive. –  Nov 13 '18 at 18:37
  • In the tests I've run, this method is **just over 10x faster than a `subprocess` call to `tasklist`** (for Windows). – S3DEV Oct 21 '19 at 10:12
  • 1
    For additional speed-up, specify `psutil.process_iter(attrs=['name'])` to only obtain the name attribute, which will be faster (marginally). https://psutil.readthedocs.io/en/latest/#psutil.process_iter – Chris Collett Oct 15 '21 at 18:51
  • @fnkr This answer doesn't use `psutil.get_pid_list`. `psutil.process_iter` is safe from this race condition based on the docs. – Chris Collett Oct 15 '21 at 18:54
  • 1
    @ChrisCollett, this also avoids the `NoSuchProcess` issue that @fnkr mentions, which is more annoying to workaround so a better reason to use your `attrs=['name']` approach – ijoseph Sep 26 '22 at 04:06
  • This works well to detect that "python" is running. But I get about a dozen such processes. Can I also find out, which script each python process is running? – ullix May 10 '23 at 06:55
26

Although @zeller said it already here is an example how to use tasklist. As I was just looking for vanilla python alternatives...

import subprocess

def process_exists(process_name):
    call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
    # use buildin check_output right away
    output = subprocess.check_output(call).decode()
    # check in last line for process name
    last_line = output.strip().split('\r\n')[-1]
    # because Fail message could be translated
    return last_line.lower().startswith(process_name.lower())

and now you can do:

>>> process_exists('eclipse.exe')
True

>>> process_exists('AJKGVSJGSCSeclipse.exe')
False

To avoid calling this multiple times and have an overview of all the processes this way you could do something like:

# get info dict about all running processes
import subprocess
output = subprocess.check_output(('TASKLIST', '/FO', 'CSV')).decode()
# get rid of extra " and split into lines
output = output.replace('"', '').split('\r\n')
keys = output[0].split(',')
proc_list = [i.split(',') for i in output[1:] if i]
# make dict with proc names as keys and dicts with the extra nfo as values
proc_dict = dict((i[0], dict(zip(keys[1:], i[1:]))) for i in proc_list)
for name, values in sorted(proc_dict.items(), key=lambda x: x[0].lower()):
    print('%s: %s' % (name, values))
ewerybody
  • 1,443
  • 16
  • 29
10

win32ui.FindWindow(classname, None) returns a window handle if any window with the given class name is found. It raises window32ui.error otherwise.

import win32ui

def WindowExists(classname):
    try:
        win32ui.FindWindow(classname, None)
    except win32ui.error:
        return False
    else:
        return True

if WindowExists("DropboxTrayIcon"):
    print "Dropbox is running, sir."
else:
    print "Dropbox is running..... not."

I found that the window class name for the Dropbox tray icon was DropboxTrayIcon using Autohotkey Window Spy.

See also

MSDN FindWindow

Jisang Yoo
  • 3,670
  • 20
  • 31
  • Thanks, I really like this method. My only objection is that I could not find the class name for my application, even with a program like AHK Window Spy. I ended up using [WMIC](https://stackoverflow.com/questions/3429250/determining-running-programs-in-python) `import subprocess cmd = 'WMIC PROCESS get Caption,Commandline,Processid' proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) for line in proc.stdout: print line` – TechDude Sep 07 '14 at 19:10
  • 1
    You can get it without subprocess --> procList = wmi.WMI ().Win32_Process () print "\n".join (proc.Caption for proc in procList) – user3885927 Sep 22 '14 at 22:04
7

I'd like to add this solution to the list, for historical purposes. It allows you to find out based on .exe instead of window title, and also returns memory used & PID.

processes = subprocess.Popen('tasklist', stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE).communicate()[0]
# Put a regex for exact matches, or a simple 'in' for naive matches

A slice of example output:

notepad.exe                  13944 Console                    1     11,920 K
python.exe                    5240 Console                    1     28,616 K
conhost.exe                   9796 Console                    1      7,812 K
svchost.exe                   1052 Services                   0     18,524 K
iTunes.exe                    1108 Console                    1    157,764 K
std''OrgnlDave
  • 3,912
  • 1
  • 25
  • 34
7

Try this code:

import subprocess
def process_exists(process_name):
    progs = str(subprocess.check_output('tasklist'))
    if process_name in progs:
        return True
    else:
        return False

And to check if the process is running:

if process_exists('example.exe'):
    #do something
mg34
  • 71
  • 1
  • 2
7

Lock files are generally not used on Windows (and rarely on Unix). Typically when a Windows program wants to see if another instance of itself is already running, it will call FindWindow with a known title or class name.

def iTunesRunning():
    import win32ui
    # may need FindWindow("iTunes", None) or FindWindow(None, "iTunes")
    # or something similar
    if FindWindow("iTunes", "iTunes"):
        print "Found an iTunes window"
        return True
Gabe
  • 84,912
  • 12
  • 139
  • 238
  • 1
    This might work for iTunes, but what about processes that can run as a headless instance for example Excel. This approach will not work for those applications. – anijhaw Oct 16 '11 at 21:36
  • I think the question was quite specific about wanting to check for iTunes. – Clare Macrae Oct 16 '11 at 22:12
  • 1
    @anijhaw: Are you suggesting that Excel will be running without a window, or that `FindWindow` won't find Excel's hidden window? – Gabe Oct 16 '11 at 22:42
  • 1
    Thanks win32ui.FindWindow('iTunes,'iTunes') will do the work (Y) – nightf0x Oct 17 '11 at 06:37
  • Yes excel can run a headless instance without a window – anijhaw Oct 17 '11 at 20:31
  • @anijhaw: Just because the window isn't visible, that doesn't mean it doesn't exist. When Excel is running and you don't see its window, the window is still there. – Gabe Oct 17 '11 at 20:56
  • I am not a 100% sure but I will definitely try it. – anijhaw Oct 17 '11 at 23:02
  • @anijhaw: Look for a window with class `XLMAIN`. – Gabe Oct 18 '11 at 01:16
  • win32ui.FindWindow doesn't return a falsy value when no window is found. Instead it raises an error. Also, if a seemingly headless program has a tray icon, you can still test for the tray icon. I demonstrate both points in [my answer](http://stackoverflow.com/a/12041334/1446335) – Jisang Yoo Aug 20 '12 at 16:23
3

Psutil suggested by Mark, is really the best solution, its only drawback is the GPL compatible license. If that's a problem, then you can invoke Windows' process info commands: wmic process where WMI is available (XP pro, vista, win7) or tasklist. Here is a description to do it: How to call an external program in python and retrieve the output and return code? (not the only possible way...)

Community
  • 1
  • 1
zeller
  • 4,904
  • 2
  • 22
  • 40
  • 1
    Just a warning: `tasklist` truncates the name of the process on long names. For example, it truncates `exe` here: `vmware-usbarbitrator64.ex 2076 Services 0 9,348 K`. Running `wmic process` does not have this problem. – twasbrillig Apr 17 '15 at 21:44
3
import psutil

for p in psutil.process_iter(attrs=['pid', 'name']):
    if "itunes.exe" in (p.info['name']).lower():
        print("yes", (p.info['name']).lower())

for python 3.7


import psutil

for p in psutil.process_iter(attrs=['pid', 'name']):
    if p.info['name'] == "itunes.exe":
        print("yes", (p.info['name']))

This works for python 3.8 & psutil 5.7.0, windows

0m3r
  • 12,286
  • 15
  • 35
  • 71
3

According to the ewerybody post: https://stackoverflow.com/a/29275361/7530957

Multiple problems can arise:

  • Multiple processes with the same name
  • Name of the long process

The 'ewerybody's' code will not work if the process name is long. So there is a problem with this line:

last_line.lower().startswith(process_name.lower())

Because last_line will be shorter than the process name.

So if you just want to know if a process/processes is/are active:

from subprocess import check_output

def process_exists(process_name):
    call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
    if check_output(call).splitlines()[3:]:
        return True

Instead for all the information of a process/processes

from subprocess import check_output

def process_exists(process_name):
    call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
    processes = []
    for process in check_output(call).splitlines()[3:]:
        process = process.decode()
        processes.append(process.split())
    return processes
Squalo
  • 119
  • 11
  • This is great. I'll also throw in the recommendation to use `subprocess.run` as it's the newer, more succinct and more readable way to call subprocesses since Python 3.5. [Docs refer](https://docs.python.org/3/library/subprocess.html#older-high-level-api) to `call`, `check_call` and `check_output` as the older API, albeit without deprecating them yet. [This answer](https://stackoverflow.com/a/41172862/2005759) does a good job summarizing `run`. – Antrikshy Feb 05 '22 at 20:13
2

If can't rely on the process name like python scripts which will always have python.exe as process name. If found this method very handy

import psutil
psutil.pid_exists(pid)

check docs for further info http://psutil.readthedocs.io/en/latest/#psutil.pid_exists

Akram
  • 453
  • 4
  • 21
2

There is a python module called wmi.

import wmi
c=wmi.WMI()
def check_process_running(str_):
    if(c.Win32_Process(name=str_)):
        print("Process is running")
    else:
        print("Process is not running")

         
check_process_running("yourprocess.exe")  
A. Faiyaz
  • 46
  • 3
2

Would you be happy with your Python command running another program to get the info?

If so, I'd suggest you have a look at PsList and all its options. For example, The following would tell you about any running iTunes process

PsList itunes

If you can work out how to interpret the results, this should hopefully get you going.

Edit:

When I'm not running iTunes, I get the following:

pslist v1.29 - Sysinternals PsList
Copyright (C) 2000-2009 Mark Russinovich
Sysinternals

Process information for CLARESPC:

Name                Pid Pri Thd  Hnd   Priv        CPU Time    Elapsed Time
iTunesHelper       3784   8  10  229   3164     0:00:00.046     3:41:05.053

With itunes running, I get this one extra line:

iTunes              928   8  24  813 106168     0:00:08.734     0:02:08.672

However, the following command prints out info only about the iTunes program itself, i.e. with the -e argument:

pslist -e itunes
Clare Macrae
  • 3,670
  • 2
  • 31
  • 45
  • I guess this would be equivalent to - os.popen('query process') and reading the lines of output and then searching for iTuens. For I actually want is to make the method simpler. as in os.stat(file). As I intend to keep the script running all the time. – nightf0x Oct 16 '11 at 20:45
  • Well, you could always just query it periodically, e.g. once a second, depending on how frequently you need to check. – Clare Macrae Oct 16 '11 at 20:53
  • I guess this is one solution that will work. Still hoping that someone might be able to shed some light on whether or not lock files are created by programs in windows. Thanks – nightf0x Oct 16 '11 at 20:59
  • OK, I've just added another answer, with info to help you try and track that down yourself. – Clare Macrae Oct 16 '11 at 21:09
  • That answer described using Process Monitor to track what files iTunes created at start-up, to see if there were any indicator files that were created. – Clare Macrae Oct 17 '11 at 05:27
1

This method below can be used to detect whether the process [ eg: notepad.exe ] is runing or not.

from pymem import Pymem
import pymem

while (True):

    try:

        pm = Pymem('notepad.exe')
        print('Notepad Started And Is Running....')

    except:

        print ('Notepad Is Not Running....')

Pymem Package Is Needed. To Install It,

pip install pymem
tfv
  • 6,016
  • 4
  • 36
  • 67
1

I liked the solution of @ewerybody with this little change

import subprocess

def process_exists(process_name):
    call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
    # use buildin check_output right away
    output = subprocess.check_output(call).decode()

    # check in last line for process name
    last_line = output.split('\r\n')
    
    #first result is 3 because the headers
    #or in case more than one, you can use the last one using [-2] index
    data = " ".join(last_line[3].split()).split()  

    #return a list with the name and pid 
    return( [data[0], data[1]] )  
Oscar Albert
  • 803
  • 8
  • 13
0

This works nicely

def running():
    n=0# number of instances of the program running 
    prog=[line.split() for line in subprocess.check_output("tasklist").splitlines()]
    [prog.pop(e) for e in [0,1,2]] #useless 
    for task in prog:
        if task[0]=="itunes.exe":
            n=n+1
    if n>0:
        return True
    else:
        return False
0

If you are testing application with Behave you can use pywinauto. Similar with previously comment, you can use this function:

def check_if_app_is_running(context, processName):
try:
    context.controller = pywinauto.Application(backend='uia').connect(best_match = processName, timeout = 5)
    context.controller.top_window().set_focus()
    return True
except pywinauto.application.ProcessNotFoundError:
    pass
return False

backend can be 'uia' or 'win32'

timeout if for force reconnect with the applicaction during 5 seconds.

Pini
  • 1
0
import subprocess as sp
for v in str(sp.check_output('powershell "gps | where {$_.MainWindowTitle}"')).split(' '):
    if len(v) is not 0 and '-' not in v and '\\r\\' not in v and 'iTunes' in v: print('Found !')
0
import psutil

def check_process_status(process_name):
    """
    Return status of process based on process name.
    """
    process_status = [ proc.status() for proc in psutil.process_iter() if proc.name() == process_name ]
    if process_status:
        print("Process name %s and staus %s"%(process_name, process_status[0]))
    else:
        print("Process name not valid", process_name)
Viraj Wadate
  • 5,447
  • 1
  • 31
  • 29
0

Psutil is the best solution for this.

import psutil

processes = list(p.name() for p in psutil.process_iter())
# print(processes)
count = processes.count("<app_name>.exe")

if count == 1:
    logging.info('Application started')
    # print('Application started')
else:
    logging.info('Process is already running!')
    # print('Process is already running!')
    sys.exit(0)                          # Stops duplicate instance from running
Voldemort
  • 175
  • 5
  • 20
0

You can just use os.kill sending a 0 signal (that doesn't kill the process) and checking for errors.

from os import kill

def check_if_running(pid):
    try:
        kill(pid, 0)
    except:
        return False
    return True
thalescr
  • 101
  • 1
  • 4
0
if tasklist.find("chrome.exe") > 0:
    os.system("taskkill /im chrome.exe")  # kill if it is running.
S.B
  • 13,077
  • 10
  • 22
  • 49