ptree - plstree - ps and ls displayed as a tree
(HTM) git clone git://bitreich.org/plstree git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/plstree
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Tags
(DIR) README
---
ptree (3515B)
---
1 #!/usr/bin/awk -f
2
3 # pstree implementation in awk
4
5 # Use ps(1) to generate a list of pid, ppid and other properties with
6 # the command name, displayed as a tree built from the pid-ppid pairs:
7 #
8 # USER TT NI PID STAT COMMAND
9 # root ? 0 1 Ss runit
10 # josuah ? 0 22437 S ├─ startx
11 # josuah ? 0 22451 S │ └─ xinit
12 # root tty7 0 22452 Rsl+ │ ├─ Xorg
13 # josuah ? 0 22457 S │ └─ dwm
14 # josuah ? 0 24882 S └─ runsvdir
15 # josuah ? 0 24884 S ├─ runsv
16 # josuah ? 0 24887 S │ ├─ svlogd
17 # josuah ? 0 24890 S │ └─ ratox
18 # josuah ? 0 24885 S └─ runsv
19 # josuah ? 0 24405 S ├─ tor
20 # josuah ? 0 24889 S └─ svlogd
21
22 BEGIN {
23 LINE = "│ ";
24 NODE = "├─ ";
25 TAIL = "└─ ";
26 VOID = " ";
27
28 list(entries);
29 NUM = 1; fill(entries, 1, 0);
30 tree(entries, NUM);
31
32 for (i = 1; i < NUM; i++) {
33 printf("%s", entries[i":info"]);
34 for (j = 1; entries[i":"j] != ""; j++)
35 printf("%s", entries[i":"j]);
36 printf("%-" 30 - j * 3 "s", entries[i":comm"]);
37 print(entries[i":args"]);
38 }
39 }
40
41 # Build a relational database in <entries> from the output of ps: The
42 # parent pid (ppid) -> pid pairs are used to accumulate a list of child
43 # pid (serialized into a csv: ",234,532,454") later used for building
44 # the tree.
45 #
46 # For each pid, "info" and "comm" are saved as well.
47
48 function list(entries)
49 {
50 opt = "-o ppid,user,vsz,pid,stat,comm,args"
51 cmd = "exec ps -ax " opt " 2>/dev/null";
52 if (!(cmd | getline)) {
53 cmd = "exec ps " opt
54 cmd | getline;
55 }
56 sub(" *[^ ]+", "");
57 print $0;
58
59 for (num = 0; cmd | getline; num++) {
60 ppid = $1; pid = $4;
61 entries[ppid"cpid"] = entries[ppid"cpid"] "," pid;
62 sub(" *[^ ]+", "");
63 sub(" *[^ ]+ + *[^ ]+ + *[^ ]+ + *[^ ]+ +", "&\t");
64 sub("[^\t]+ [^ ]+ +", "&\t");
65 split($0, info, "\t");
66 sub(" *$" , "", info[2]);
67 entries[pid"info"] = info[1];
68 entries[pid"comm"] = info[2];
69 entries[pid"args"] = info[3];
70 }
71 close(cmd);
72
73 return num - 1;
74 }
75
76 # Using the informations from the child pid in entries, build the absolute
77 # path from PID 1 to each pid:
78 #
79 # [ 1:[ 1:"1" ],
80 # 2:[ 1:"1", 2:"456" ],
81 # 3:[ 1:"1", 2:"456", 3:"1623" ],
82 # 4:[ 1:"1", 2:"456", 3:"1721" ] ]
83 #
84 # With also ":info" and ":comm" for every row.
85 #
86 # Only the leaves are present, the intermediates components are LINE or
87 # NODE if just before a leave
88 #
89 # [ 1:[ 1:LINE, 2:LINE, 3:LINE, 4:LINE, 5:NODE, 6:"filename" ] ]
90
91 function fill(entries, pid, lvl)
92 {
93 for (j = 0; j < lvl; j++)
94 entries[NUM":"j] = LINE;
95 entries[NUM":"lvl] = NODE;
96 entries[NUM":comm"] = entries[pid"comm"];
97 entries[NUM":args"] = entries[pid"args"];
98 entries[NUM":info"] = entries[pid"info"];
99 NUM++;
100 while (sub("[^,]*,", "", entries[pid"cpid"])) {
101 cpid = entries[pid"cpid"];
102 sub(",.*", "", cpid);
103 fill(entries, cpid, lvl + 1);
104 }
105 }
106
107 # Transform entries into a tree by replacing some LINE by VOID when needed.
108 # The tree is walked from the bottom to the top, and column by column
109 # toward the right until an empty column is met.
110
111 function tree(entries, num)
112 {
113 for (j = 0; !stop; j++) {
114 stop = tail = 1;
115 for (i = num; i > 0; i--) {
116 if (entries[i":"j] == LINE && tail) {
117 entries[i":"j] = VOID;
118 stop = 0;
119 } else if (entries[i":"j] == NODE && tail) {
120 entries[i":"j] = TAIL;
121 tail = stop = 0;
122 } else if (!entries[i":"j]) {
123 tail = 1;
124 }
125 }
126 }
127 }