Table of Contents
PS Package
What is it?
The ps
package is a couple of simple classes I created to wrap a system call to /bin/ps
on a *nix machine. This will parse the output of that call and give you an easy to use object that has some simple accessor functions for finding what you want in the ps output or by letting you iterate over the object itself and accessing the information for each running process.
The Script
#!/usr/bin/env python # $Id: ps.py,v 1.5 2008/04/24 03:37:05 jay Exp $ """ This will run a system call of '/bin/ps auxww' and parse the results and put them in object containers for easy access to the data. Usage: import ps myps = ps.PS() for row in myps: for col in row: print '%s: %s' % (col , row[col]) # You can also access the row items by name for row in myps: print row.pid # OR... print row['pid'] # You can search for a particular process or processes rows = myps.getProcByName('firefox(?:-bin)?') for row in rows: print '%s: %s' % (row.pid , row.command) # Get all the processes for a given user rows = myps.getByUser('username') for row in rows: print '%s: %s' % (row.pid , row.command) # Get the info for a given pid number pidNum = open('/var/run/myproc.pid').read() row = myps.getByPid(pidNum) if row: print '%s: %d' % (row.command , row.cpu_perc) """ import os , re __all__ = ['PS' , 'PSRow'] class PS(object): """ This is the callable class. This will create an array of accessible PSRow objects that contain all the info for current ps output. """ def __init__(self , psPath='/bin/ps' , psArgs='auxww'): """ psPath: This should be the path to the ps binary on your system. default: /bin/ps psArgs: These are the args to be used when calling ps. See "man ps" for more information. default: auxww """ self._rows = [] self._rawCols = [] self._psPath = psPath self._psArgs = psArgs self._cmd = '%s %s' % (self._psPath , self._psArgs) self._curNum = 0 self.refresh() def _runCommand(self): """ This actually runs the command and creates the array """ ps = os.popen(self._cmd) self._setRawCols(ps.readline()) while True: line = ps.readline() if not line: break self._rows.append(PSRow(line , self._rawCols)) ps.close() def getRows(self): """ getRows() -> Returns a list of PSRow objects """ return self._rows Rows = property(getRows) def getRawCols(self): """ getRawCols() -> Returns a list of strings pertaining to the column headers """ return self._rawCols def _setRawCols(self , line): for c in re.split(r'\s+' , line.strip()): if '%' in c: c = c.replace('%' , '') + '_perc' self._rawCols.append(c.lower()) RawCols = property(getRawCols) def getByPid(self , pid): """ Returns a PSRow object pertaining to the pid number or None if it does not exist """ for row in self._rows: if 'pid' not in row: return None if int(row.pid) == int(pid): return row return None def getByUser(self , username): """ Returns a list of PSRow objects for the given username """ ret = [] for row in self._rows: if 'user' not in row: return None if row.user == username: ret.append(row) return ret def getProcByName(self , search): """ Returns a list of PSRow objects based on a search of the executed commands given the PCRE string "search". """ ret = [] reg = re.compile(search) for row in self._rows: if 'command' not in row: return None if reg.search(row.command): ret.append(row) return ret def refresh(self): """ Refreshes the current rows of ps output by performing another run of ps. """ self._rows = [] self._rawCols = [] self._runCommand() def __iter__(self): """ Makes the PS object iterable """ return PS._iter(self) def _iter(self): """ Iterates over the rows of PSRow objects for the given instance """ for psr in self._rows: yield psr class PSRow(object): """ This is a data structure holding all the results of a row of ps output """ def __init__(self , s , cols): """ s: The string pertaining to one row of ps output cols: A list of the column header names """ self.cols = cols self.items = {} self._parseStr(s) def _parseStr(self , s): """ Parses the ps output row string into members of this object """ items = re.split(r'\s+' , s.strip() , len(self.cols) - 1) self.items = dict(zip(self.cols , items)) self.__dict__.update(self.items) def __contains__(self , k): """ Returns true if the string, k, pertains to a member of this object For example, if you wanted to know if there was a "user" column available from the ps output you could do the following: if 'user' in psrow: print psrow.user """ return k in self.items def __iter__(self): """ Makes the PSRow object iterable """ return PSRow._iter(self) def _iter(self): """ Iterates over the keys in the PSRow object """ for c in self.items.keys(): yield c def __getitem__(self , name): """ Allows for dictionary access to the row items: print psrow['user'] """ if name in self.items: return self.items[name]
Usage
This is meant to be used purely as a library. Here is a simple example. Run pydoc ps
for more information.
import ps myps = ps.PS() # Show each running process as a block for row in myps: for col, val in row.items(): print '%s: %s' % (col , val) print
After installing, run pydoc ps
for more information.
Install
Simply download the script or copy the above into a file and put the file in your lib/python<version>/site-packages
directory. This is usually something to the effect of /usr/lib/python2.4/site-packages
but it varies depending on the distro.