[Tip] ptree for Linux

Unix (and Linux) uses a process tree that gives a natural security, by simple inheritance of attributes.

The following ptree script shows it. It runs on all Linux flavors.
Mostly useful for debugging.

#!/bin/sh
# Solaris style ptree

[ -x /usr/bin/ptree ] && exec /usr/bin/ptree "$@"

PATH=/bin:/usr/bin:/usr/sbin:/sbin
export PATH

case $1 in
-*)
 echo "
Usage: ptree [ PID | USER ]
Print process tree
 PID : extract branch for this process
 USER : filter for this (existing) user
 USER PID : do both
"
 exit
;;
*[!0-9]*)
 psopt="-u $1"
 shift
;;
*)
 psopt="-e"
esac
psopt="$psopt -H -o pid= -o args="

if [ -z "$1" ]; then
 ps $psopt
 exit
fi

#some effort to add less to the ps list
tmp=/tmp/ptree.$$
trap 'rm -f $tmp' 0 HUP INT TERM
ps $psopt >$tmp
<$tmp awk '
{ ci=index(substr($0,6),$2); o[ci]=$0 }
ci>s[a] { s[++a]=ci }
$1==pid {
 for(i=1;i<=a;i++) {
  si=s; if(si<=ci) print o[si]
 }
 walkdown=ci
 next
}
ci<=walkdown { exit }
walkdown!=0 { print }
' pid="$1"

Without argument it displays the full process tree, like the pstree command.
When there is a PID argument (number), it shows the part of the process tree with the PID - that is the PID's ancestors and descendants.
Also there can be a USER argument, then it shows the USER's processes from the tree.

A quick exercise: where is my current shell from?

ptree $$
5 Likes

Quick test on macOS

macos$ cat ptree.sh
#!/bin/sh
# Solaris style ptree

[ -x /usr/bin/ptree ] && exec /usr/bin/ptree "$@"

PATH=/bin:/usr/bin:/usr/sbin:/sbin
esac
psopt="$psopt -H -o pid= -o args="

if [ -z "$1" ]; then
 ps $psopt
 exit
fi

#some effort to add less to the ps list
tmp=/tmp/ptree.$$
trap 'rm -f $tmp' 0 HUP INT TERM
ps $psopt >$tmp
<$tmp awk '
{ ci=index(substr($0,6),$2); o[ci]=$0 }
ci>s[a] { s[++a]=ci }
$1==pid {
 for(i=1;i<=a;i++) {
  si=s; if(si<=ci) print o[si]
 }
 walkdown=ci
 next
}
ci<=walkdown { exit }
walkdown!=0 { print }
' pid="$1"
macos$ echo $SHELL
/bin/bash
macos$ ./ptree.sh $$
./ptree.sh: line 7: syntax error near unexpected token `esac'
./ptree.sh: line 7: `esac'
macos$ 
macos$ /bin/sh ./ptree.sh $$
./ptree.sh: line 7: syntax error near unexpected token `esac'
./ptree.sh: line 7: `esac'
2 Likes

Hi
As I understand it a linux "pstree"
My five cents.
It comes with a built-in pager

systemd-cgls

Another option

ps xawf -eo pid,user,cgroup,args
2 Likes

Sorry, somehow my copy/paste left out a bunch of lines.
Now I have corrected my original post.

--- Post updated at 11:24 ---

@nezabudka, the goal was to only show a relevant part of the process tree.

1 Like
sh-3.2_macos$ ./mig.sh
ps: illegal option -- H
usage: ps [-AaCcEefhjlMmrSTvwXx] [-O fmt | -o fmt] [-G gid[,gid...]]
          [-g grp[,grp...]] [-u [uid,uid...]]
          [-p pid[,pid...]] [-t tty[,tty...]] [-U user[,user...]]
       ps [-L]
sh-3.2$ cat mig.sh
#!/bin/sh
# Solaris style ptree

[ -x /usr/bin/ptree ] && exec /usr/bin/ptree "$@"

PATH=/bin:/usr/bin:/usr/sbin:/sbin
export PATH

case $1 in
-*)
 echo "
Usage: ptree [ PID | USER ]
Print process tree
 PID : extract branch for this process
 USER : filter for this (existing) user
 USER PID : do both
"
 exit
;;
*[!0-9]*)
 psopt="-u $1"
 shift
;;
*)
 psopt="-e"
esac
psopt="$psopt -H -o pid= -o args="

if [ -z "$1" ]; then
 ps $psopt
 exit
fi

#some effort to add less to the ps list
tmp=/tmp/ptree.$$
trap 'rm -f $tmp' 0 HUP INT TERM
ps $psopt >$tmp
<$tmp awk '
{ ci=index(substr($0,6),$2); o[ci]=$0 }
ci>s[a] { s[++a]=ci }
$1==pid {
 for(i=1;i<=a;i++) {
  si=s; if(si<=ci) print o[si]
 }
 walkdown=ci
 next
}
ci<=walkdown { exit }
walkdown!=0 { print }
' pid="$1"
sh-3.2$ 
macos$ ./mig.sh $$
ps: illegal option -- H
usage: ps [-AaCcEefhjlMmrSTvwXx] [-O fmt | -o fmt] [-G gid[,gid...]]
          [-g grp[,grp...]] [-u [uid,uid...]]
          [-p pid[,pid...]] [-t tty[,tty...]] [-U user[,user...]]
       ps [-L]
macos$ echo $SHELL
/bin/bash
macos$ 

I'd like to mention --forest option of ps which I use regularly under linux.

It lacks the here mentioned feature to show only the tree concerning a special pid.

ps ax --forest
...
 2406 ?        S      0:00 /usr/lib/x86_64-linux-gnu/libexec/kf5/start_kdeinit --kded +kcminit_startup
 2411 ?        Ss     0:00 kdeinit5: Running...
 2413 ?        Sl     0:00  \_ /usr/lib/x86_64-linux-gnu/libexec/kf5/klauncher --fd=9
 2420 ?        Sl     0:01  \_ kded5 [kdeinit5]
 2761 ?        Sl     0:00  \_ /usr/bin/ksmserver
 2791 ?        Sl     0:09  |   \_ kwin_x11 -session 10dde16a61000157748587300000029330001_1578584288_66599
 2799 ?        Sl     0:02  |   \_ /usr/bin/krunner
 2800 ?        Sl     0:29  |   \_ /usr/bin/plasmashell --shut-up
 2801 ?        Sl     0:00  |   \_ /usr/lib/x86_64-linux-gnu/libexec/polkit-kde-authentication-agent-1
 2802 ?        Sl     0:00  |   \_ /usr/bin/xembedsniproxy
 2888 ?        Sl     0:00  |   \_ /usr/lib/at-spi2-core/at-spi-bus-launcher --launch-immediately
 2910 ?        S      0:00  |   |   \_ /usr/bin/dbus-daemon --config-file=/usr/share/defaults/at-spi2/accessibility.conf --nofork --print-address 3
 2889 ?        Sl     0:00  |   \_ /usr/bin/korgac
 2856 ?        Sl     0:01  \_ /usr/bin/owncloud -session 10dde16a61000157848162200000034850009_1578584288_58686
 3486 ?        Sl     2:15  \_ /usr/local/bin/firefox
 3634 ?        Sl     0:41  |   \_ /opt/firefox/firefox-61.0.1/firefox-bin -contentproc -childID 3 -isForBrowser -prefsLen 6100 -prefMapSize 258569 -parentBuildID 20200107212822 -greomni /opt/fire
 6193 ?        Sl     0:18  |   \_ /opt/firefox/firefox-61.0.1/firefox-bin -contentproc -childID 20 -isForBrowser -prefsLen 7615 -prefMapSize 258569 -parentBuildID 20200107212822 -greomni /opt/fir
 6565 ?        Sl     0:04  |   \_ /opt/firefox/firefox-61.0.1/firefox-bin -contentproc -childID 25 -isForBrowser -prefsLen 7615 -prefMapSize 258569 -parentBuildID 20200107212822 -greomni /opt/fir
 6687 ?        Sl     0:00  |   \_ /opt/firefox/firefox-61.0.1/firefox-bin -contentproc -childID 26 -isForBrowser -prefsLen 7615 -prefMapSize 258569 -parentBuildID 20200107212822 -greomni /opt/fir
 3968 ?        Sl     0:08  \_ /usr/bin/konsole
 3975 pts/1    Ss     0:00  |   \_ /bin/bash
 3985 pts/1    S+     0:00  |   |   \_ ssh webhost01
 5438 pts/2    Ss     0:00  |   \_ /bin/bash
 5445 pts/2    S+     0:00  |   |   \_ ssh webhost01
 6922 pts/3    Ss     0:00  |   \_ /bin/bash
 6984 pts/3    R+     0:00  |       \_ ps ax --forest
 4508 ?        Sl     0:33  \_ /usr/lib/thunderbird/thunderbird
...
2 Likes

The -H is specific to GNU ps (Linux).
It does an indentation (two spaces per hierarchy level) without any ASCII art. This is easy to post-process i.e. filter for the releavant parts.

1 Like