Let's say I run ps axf
and I can see that my command's process tree looks like this:
800 ? Ss 0:00 /usr/sbin/sshd
10186 ? Ss 0:00 \_ sshd: yukondude [priv]
10251 ? S 0:00 \_ sshd: yukondude@pts/0
10252 pts/0 Ss 0:00 \_ -bash
10778 pts/0 S 0:00 \_ su -
10785 pts/0 S 0:00 \_ -su
11945 pts/0 R+ 0:00 \_ ps axf
I know I can check $$
for the current shell's PID (10785) or $PPID
for the parent PID (10778).
But I just want the top-level parent PID, which would be 800 (SSH daemon) in this example. Is there any way to do that easily?
I learned from this SO answer that I can recursively check the 4th entry in the /proc/PID/stat
file to find each process's parent PID:
# cut -f4 -d' ' /proc/10785/stat
10778
# cut -f4 -d' ' /proc/10778/stat
10252
# cut -f4 -d' ' /proc/10252/stat
10251
# cut -f4 -d' ' /proc/10251/stat
10186
# cut -f4 -d' ' /proc/10186/stat
800
# cut -f4 -d' ' /proc/800/stat
1
(The top-level parent PID will be the one just before I reach init
's PID, i.e., 1.)
Before I write a little loop (I'm not even sure if you can use recursion in bash) to do this, is there a much more straightforward method that I'm missing? Maybe just another parameter of a file under /proc
? A grep
through those files didn't reveal anything obvious.
Edit: Of course, the top-level process for all Linux processes is /sbin/init with a PID of 1. What I want is the PID of the parent just before that: the penultimate parent.
Bash can definitely do recursion.
You can retrieve the fourth field from the stat file without using the external cut
utility by doing something like this:
stat=($(</proc/$$/stat)) # create an array
ppid=${stat[3]} # get the fourth field
If the command might have space(s) in its name, you can count from the end of the array (assuming that the number of fields is stable). This will also work if there are no spaces in the command's name.
ppid=${stat[-49]} # gets the same field but counts from the end
Here's another technique which should avoid those problems (but may fail if the command name contains a newline):
mapfile -t stat < /proc/$$/status
ppid=${stat[5]##*$'\t'}
The fifth field in that file looks like:
PPid: 1234
and the brace expansion strips the everything up to the tab character leaving just the numeric part.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With