views:

173

answers:

5

How can i get process id of the current process's parent?
In general given a process id how can I get its parent process id?
e.g. os.getpid() can be used to get the proccess id, and os.getppid() for the parent, how do I get grandparent,

My target is linux(ubuntu) so platform specific answers are ok.

A: 

I do not think you can do this portably in the general case.

You need to get this information from the process list (e.g. through the ps command), which is obtained in a system-specific way.

ddaa
don't think he cares about portability
Matt Joiner
+4  A: 

linux specific:

os.popen("ps -p %d -oppid=" % os.getppid()).read().strip()
pixelbeat
Naturally, that does not work on windows unless you have cygwin installed.
ddaa
I need it for linux some works for me, nice and simple :)
Anurag Uniyal
+1 for a simpler solution than mine.
paxdiablo
+2  A: 

I don't think you can do this in a portable Python fashion. But there are two possibilities.

  1. The information is available from the ps command so you could analyze that.
  2. If you have a system with the proc file systems, you can open the file /proc/<pid>/status and search for the line containing PPid:, then do the same for that PID.

For example the following script will get you your PID, PPID and PPPID, permissions willing:

#!/bin/bash
pid=$$
ppid=$(grep PPid: /proc/${pid}/status | awk '{print $2'})
pppid=$(grep PPid: /proc/${ppid}/status | awk '{print $2'})
echo ${pid} ${ppid} ${pppid}
ps -f -p "${pid},${ppid},${pppid}"

produces:

3269 3160 3142
UID        PID  PPID  C STIME TTY          TIME CMD
pax       3142  2786  0 18:24 pts/1    00:00:00 bash
root      3160  3142  0 18:24 pts/1    00:00:00 bash
root      3269  3160  0 18:34 pts/1    00:00:00 /bin/bash ./getem.sh

Obviously, you'd have to open those files with Python.

paxdiablo
+1 good working example, but pixelbeat's answer works easily, any caveat there?
Anurag Uniyal
No, pixelbeat's looks fine and, in fact, I've upvoted it since it's a tad simpler than my method - I wasn't aware of those options to ps, having come from the *very* early UNIX days :-)
paxdiablo
I edited your answer (the ps line). Using grep to filter ps output can give incorrect results (think if pppid was 1, for example).The -p option, by the way, is quite old.
ΤΖΩΤΖΙΟΥ
No problems, ΤΖΩΤΖΙΟΥ, that was really just to show that the three figures were correct, not actually part of the answer. But I'll be using that -p option from now on in lieu of grep.
paxdiablo
A: 

If you have a POSIX-compliant 'ps' command, which allows you to specify the columns you want, like this: ps -o pid,ppid

You could then try:

import os
import re

ps = os.popen("ps -o pid,ppid")
ps.readline()    # discard header
lines = ps.readlines()
ps.close

procs = [ re.split("\s+", line.strip()) for line in lines ]

parent = {}
for proc in procs:
    parent[ int(proc[0]) ] = int(proc[1])

Now you can do:

parent[ parent[pid] ]

You could even write a function to list a process' ancestors:

def listp(pid):
    print(pid)
    if parent.has_key(pid):
        listp( parent[pid] )
Nick Dixon
line.split() will work instead of re.split(r"\s+", line.strip()). The default split() splits on \s+ and removes leading and trailing whitespace.
Andrew Dalke
A: 
from __future__ import with_statement

def pnid(pid=None, N=1):
    "Get parent (if N==1), grandparent (if N==2), ... of pid (or self if not given)"
    if pid is None:
        pid= "self"

    while N > 0:
        filename= "/proc/%s/status" % pid
        with open(filename, "r") as fp:
            for line in fp:
                if line.startswith("PPid:"):
                    _, _, pid= line.rpartition("\t")
                    pid= pid.rstrip() # drop the '\n' at end
                    break
            else:
                raise RuntimeError, "can't locate PPid line in %r" % filename
        N-= 1

    return int(pid) # let it fail through


>>> pnid()
26558
>>> import os
>>> os.getppid()
26558
>>> pnid(26558)
26556
>>> pnid(N=2)
26556
>>> pnid(N=3)
1
ΤΖΩΤΖΙΟΥ
btw, I've had people often ask me why I don't follow PEP-8 and never use a space after a name when assigning to it; it's an old habit I developed for C code and kept it; it's been years since I last got bitten by a "=" instead of "==" bug (or syntax error).
ΤΖΩΤΖΙΟΥ
+1 for pnid, but wouldn't recursive "ps -p %d -oppid=" % pid would be much shorter and clear
Anurag Uniyal
This is a single process python script; I find a recursive `ps` more appropriate for a shell script. I don't treat python as a generic /bin/sh replacement. Thanks for the "+1" in your comment, anyway.
ΤΖΩΤΖΙΟΥ