There is also the issue of correctness. Naively parsing the output of pstree is problematic for several reasons:
- pstree displays PIDs and the ids of threads (names are shown in curly braces)
- a command name might contain curly braces, numbers in parentheses that make reliable parsing impossible
If you have Python and the psutil package installed you can use this snippet to list all descendant processes:
pid=2235; python3 -c "import psutil
for c in psutil.Process($pid).children(True):
print(c.pid)"
(The psutil package is e.g. installed as a dependency of the tracer command which is available on Fedora/CentOS.)
Alternatively, you can do an breadth-first traversal of the process tree in a bourne shell:
ps=2235; while [ "$ps" ]; do echo $ps; ps=$(echo $ps | xargs -n1 pgrep -P); \
done | tail -n +2 | tr " " "\n"
For computing the transitive-closure of a pid, the tail part can be omitted.
Note that the above doesn't use recursion and also runs in ksh-88.
On Linux, one can eliminate the pgrep call and instead read the information from /proc:
ps=2235; while [ "$ps" ]; do echo $ps ; \
ps=$(for p in $ps; do cat /proc/$p/task/$p/children; done); done \
| tr " " "\n"' | tail -n +2
This is more efficient because we save one fork/exec for each PID and pgrep does some additional work in each call.
'\n'delimited vs.' 'delimited). Practical use case is: a) a daemonizer script I wrote out of pure masochism (specifically, the "stop" functionality has to deal with whatever tree of processes the daemonized process spawned); and b) a timeout script that will kill whatever the timed-out process managed to create.kill. See unix.stackexchange.com/questions/9480/…, unix.stackexchange.com/questions/50555/…ps ax -opid,ppid,pgrp,cmdI see there are many processes that share the samepgrpas the exact subtree I want to kill. (Additionally, I can't see thesetpgrpprogram listed anywhere in debian stable packages: packages.debian.org/… )