0

I have a slightly different process tree question. I need to list the process and their depth in scalar value. pstree gives the result in a "graphic" manner.

root      100930  0.0  0.3 839396 49020 ?        Ssl  Aug15  38:20 /usr/sbin/rsyslogd -n
root      847414  0.0  0.0  76640  7788 ?        Ss   Aug24   0:00 /usr/sbin/sshd -D 
root     2471773  0.0  0.0 161028 11436 ?        Ss   16:26   0:00  \_ sshd: root [priv]
root     2471790  0.0  0.0 161028  6492 ?        S    16:26   0:00      \_ sshd: root@pts/0
root     2471791  0.0  0.0  17064  5744 pts/0    Ss   16:26   0:00          \_ -bash
root     2483408  0.0  0.0  48064  4260 pts/0    R+   19:13   0:00              \_ ps auxf

However would be better to list in table and be able to filter process with depth > 3, 4, 5, etc.

PID PARENT PID DEPTH PROCESS
100930 1 rsyslogd
847414 1 sshd
2471773 847414 2 sshd
2471790 2471773 3 sshd
2471791 2471790 4 bash
2483408 2471791 5 ps auxf

Any ideas?

PS: These question are similar but not exactly what I mean. How to retrive information like PID, PPID, Depth in bash of all processes? How many deep shells I am?

0

1 Answer 1

3

On my OpenBSD system (also tested on Ubuntu):

$ ps -o pid=,ppid=,command= -ax | awk '{ parent[$1] = $2; cmd[$1] = $3 } function depth(p) { if (p == "" || p == 1) return 1; else return depth(parent[p]) + 1 } END { for (p in parent) print p, parent[p], depth(p), cmd[p] }' | mlr --n2p --barred label PID,PPID,Depth,Command then sort -n Depth,PID
+-------+-------+-------+---------------------------+                                                                                                               01:51:28 [30/1957]
| PID   | PPID  | Depth | Command                   |
+-------+-------+-------+---------------------------+
| 1     | 0     | 1     | /sbin/init                |
| 5555  | 1     | 2     | /usr/sbin/smtpd           |
| 8624  | 1     | 2     | /usr/local/sbin/obsdfreqd |
| 11258 | 1     | 2     | ssh:                      |
...
| 25177 | 78190 | 4     | tmux:                     |
| 39399 | 42657 | 4     | zsh                       |
| 61862 | 42657 | 4     | awk                       |
| 90021 | 65371 | 4     | /usr/local/bin/syncthing  |
+-------+-------+-------+---------------------------+

The command pipeline, pretty-printed:

ps -o pid=,ppid=,command= -ax |
awk '
{
    parent[$1] = $2
    cmd[$1] = $3
}
function depth(p) {
    if (p == "" || p == 1)
        return 1
    else
        return depth(parent[p]) + 1
}
END {
    for (p in parent)
        print p, parent[p], depth(p), cmd[p]
}' |
mlr --n2p --barred \
    label PID,PPID,Depth,Command then \
    sort -n Depth,PID

The ps command provides the raw input data and does so by outputting the PID, PPID, and the command string of every process on the system.

This is read by awk and we store the parent for each PID in the parent array, and the first word of the command in the cmd array. These arrays are keyed on the PID.

The awk code then outputs the PID, PPID, depth, and the first word of the command string for each PID. The depth is calculated by the recursive function depth, which traces the PID back to the process with PID 1 (or with no parent; this occurred on a system with lots of various containers running on it), and then propagates the accumulation of depth back to the caller.

The mlr command at the end is purely for formatting and sorting the output. It uses Miller to read the space-delimited data, label it, sort it on the depth and PID fields, and then produce a pretty-printed tabular output. That mlr command could probably be replaced with

sort -k 3,3n -k 1,1n | column -t

As for filtering on the depth, this would be trivial with Miller as you could just add another processing step with then followed by e.g. filter '$Depth > 3'.

You could also filter with awk if you don't want to use Miller. Piping the output of column -t through awk '$3 > 3' would extract all lines with a depth greater than three. You could also make the print statement of the larger awk code conditional on the depth:

END {
    for (p in parent)
        if ((d = depth(p)) > 3)
            print p, parent[p], d, cmd[p]
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .