ps: How can i recursively get all child process for a given pid
Solution 1
The pstree
is a very good solution, but it is a little bit reticent. I use ps --forest
instead. But not for a PID
(-p
) because it prints only the specific process, but for the session (-g
). It can print out any information ps
can print in a fancy ASCII art tree defining the -o
option.
So my suggestion for this problem:
ps --forest -o pid,tty,stat,time,cmd -g 2795
If the process is not a session leader, then a little bit more trick has to be applied:
ps --forest -o pid,tty,stat,time,cmd -g $(ps -o sid= -p 2795)
This gets the session id (SID) of the current process first and then call ps again with that sid.
If the column headers are not needed add a '=' after each column definition in '-o' options, like:
ps --forest -o pid=,tty=,stat=,time=,cmd= -g $(ps -o sid= -p 2795)
An example run and the result:
$ ps --forest -o pid=,tty=,stat=,time=,cmd= -g $(ps -o sid= -p 30085)
27950 pts/36 Ss 00:00:00 -bash
30085 pts/36 S+ 00:00:00 \_ /bin/bash ./loop.sh
31888 pts/36 S+ 00:00:00 \_ sleep 5
Unfortunately this does not work for screen
as it sets the sid for each child screen and all grandchild bash.
To get all the processes spawned by a process the whole tree needs to be built. I used awk for that. At first it builds a hash array to contain all PID => ,child,child...
. At the end it calls a recursive function to extract all the child processes of a given process. The result is passed to another ps
to format the result. The actual PID has to be written as an argument to awk instead of <PID>
:
ps --forest $(ps -e --no-header -o pid,ppid|awk -vp=<PID> 'function r(s){print s;s=a[s];while(s){sub(",","",s);t=s;sub(",.*","",t);sub("[0-9]+","",s);r(t)}}{a[$2]=a[$2]","$1}END{r(p)}')
For a SCREEN process (pid=8041) the example output looks like this:
PID TTY STAT TIME COMMAND
8041 ? Ss 0:00 SCREEN
8042 pts/8 Ss 0:00 \_ /bin/bash
8092 pts/8 T 0:00 \_ vim test_arg test_server
12473 pts/8 T 0:00 \_ vim
12972 pts/8 T 0:00 \_ vim
Solution 2
pstree ${pid}
where ${pid}
is the pid of the parent process.
On Gentoo Linux, pstree
is in the package "psmisc," apparently located at http://psmisc.sourceforge.net/
Solution 3
Here is my version that runs instantly (because ps
executed only once). Works in bash and zsh.
pidtree() (
[ -n "$ZSH_VERSION" ] && setopt shwordsplit
declare -A CHILDS
while read P PP;do
CHILDS[$PP]+=" $P"
done < <(ps -e -o pid= -o ppid=)
walk() {
echo $1
for i in ${CHILDS[$1]};do
walk $i
done
}
for i in "$@";do
walk $i
done
)
Solution 4
ps -H -g "$pid" -o comm
doesn't add a tree per se, it is just the list of processes.
gives for example
COMMAND
bash
nvim
python
Solution 5
I've created a small bash script to create a list pid's of a parent's child process(es). Recursively till it finds the last child process which does not have any childs. It does not give you a tree view. It just lists all pid's.
function list_offspring {
tp=`pgrep -P $1` #get childs pids of parent pid
for i in $tp; do #loop through childs
if [ -z $i ]; then #check if empty list
exit #if empty: exit
else #else
echo -n "$i " #print childs pid
list_offspring $i #call list_offspring again with child pid as the parent
fi;
done
}
list_offspring $1
first argument of list_offspring is the parent pid
Related videos on Youtube
kynan
Updated on September 18, 2022Comments
-
kynan over 1 year
How can I get the entire process tree spawned by a given process displayed as a tree and only that tree i.e. no other processes?
The output could e.g. look like
4378 ? Ss 0:10 SCREEN 4897 pts/16 Ss 0:00 \_ -/bin/bash 25667 pts/16 S+ 0:00 | \_ git diff 25669 pts/16 S+ 0:00 | \_ less -FRSX 11118 pts/32 Ss+ 0:00 \_ -/bin/bash 11123 pts/32 S+ 0:00 \_ vi
I couldn't get the desired result purely with parameters to
ps
.The following gives the desired result but seems a bit involved:
#!/bin/bash pidtree() { echo -n $1 " " for _child in $(ps -o pid --no-headers --ppid $1); do echo -n $_child `pidtree $_child` " " done } ps f `pidtree 4378`
Does anyone have an easier solution?
-
jftuga over 12 yearsNot an answer, but start with
ps auxf
. -
kynan over 12 years@jtfuga This is in fact where I started, but this gives me all processes, which is exactly what I don't want.
-
-
kynan over 12 yearsThanks, should have mentioned that I had looked at
pstree
, but missed a more verbose output format. However,pstree -p <pid>
at least print the pids which is reasonably close. -
Aquarius Power almost 10 yearsI have this problem too, I need to gather all child pids recursively but I need only the pids, so I would have to
sed
all that.. mmm this works :)pstree -pn 4008 |grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*"
-
David Richerby almost 9 yearsThere are already several other answers that give a bash script that doesn't print an actual tree, including one in the question itself. What advantages does your (partial) answer have over the existing (partial) answers?
-
Merijn almost 9 yearsI used recursion and added some explanation. Thought it might help someone. It does exactly what the title asks for.
-
user 99572 is fine about 8 yearsPlease explain some more why this answers the question.
-
John Szakmeister almost 8 yearsI like the use of pgrep here, since ps can differ among unix variants.
-
Mark Lakata over 7 yearsThis also prints out the pid of the current process, which you may or may not want. I didn't want the current process listed (just descendants of the current process), so I changed the script by moving
echo $1
inside the first for loop and changing it toecho $i
. -
Anthony Geoghegan over 7 yearsThe
-H
option is used to display a process tree or "process hierarchy (forest)" -
Armand almost 7 yearsI was just about to write such a function when I found this. This is the only solution that seems to work on MacOS, Linux, and Solaris. Great work. Love that you rely on a single run of ps to get the job done in memory.
-
Armand almost 7 yearsThe issue with this (I know, it's an old answer) is the --forest option only works on Linux (or other gnu based "ps" commands). Solaris, and MacOS don't like it.
-
Bionix1441 over 6 years@TrueY do you know of a C API that can do that ? Thank you
-
TrueY over 6 yearsBionix No, sorry... I may read /proc/<PID> directories to build that tree.
-
CMCDragonkai over 5 yearsSeems like this should be simple if
ps
had a filter flag option just to filter to all descendants of a PID. -
Irfan Latif about 4 yearsSimple and splendid.
-
x-yuri about 4 yearsRegarding your last
awk
oneliner, I wonder if it has to be that complex? -
Matiullah Khan about 3 yearsI like
ps -fH -g <pid>
as an quick approximation to your answer :) -
Admin almost 2 yearsThanks you for the inspiration. I made a POSIX compliant version of it: superuser.com/a/1721354/114255