ptree - plstree - ps and ls displayed as a tree HTML 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 }