plstree

display ls or ps output as directory or process trees
Log | Files | Refs | README

commit 35d52859f6fcd9f3d9e411584784f4ccd4b75b87
Author: Josuah Demangeon <mail@josuah.net>
Date:   Thu, 19 Apr 2018 04:02:41 +0200

initial import from ~/bin

Diffstat:
Alstree | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apstree | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atree | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 296 insertions(+), 0 deletions(-)

diff --git a/lstree b/lstree @@ -0,0 +1,98 @@ +#!/usr/bin/awk -f + +# list paths in a tree with some stat infos + +# Use find(1) walk the entire tree and then call ls -ld with all the +# result (ls sort the list itself) with the paths displayed as a tree: +# +# drwxr-xr-x 2 josuah josuah 512 Feb 16 13:19 |- .ssh +# -rw-r--r-- 1 josuah josuah 870 Feb 9 02:24 | `- config +# drwxr-xr-x 2 josuah josuah 1536 Feb 18 21:24 |- bin +# -rwxr-xr-x 1 josuah josuah 1351 Feb 18 22:30 | |- lt +# -rwxr-xr-x 1 josuah josuah 565 Feb 17 19:53 | |- mfilter +# -rwxr-xr-x 1 josuah josuah 5430 Feb 17 19:51 | `- xdg-open +# -rwxr-xr-x 1 josuah josuah 468 Feb 17 19:55 ... + +BEGIN { + LINE = "| "; + NODE = "|- "; + TAIL = "`- "; + VOID = " "; + + num = list(entries, ARGC == 1 ? "." : ARGV[1]); + tree(entries, num); + + for (l = 1; l <= num; l++) { + for (i = 1; entries[l":"i] != ""; i++) + printf("%s", entries[l":"i]); + printf("%s\n", entries[l"name"]); + } +} + +# Get a recursive list of all entries into entries[] with entries[i:j] +# holding the component j of the path i, and 0 has all the -l details, +# then return the number of entries in entries[]. +# +# [ 1:[ 0:"-rw-r--r-- 1 root root 341 Mar 13 10:50", +# 1:"etc" ], +# 2:[ 0:"drwxr-xr-x 28 root root 4096 Mar 13 10:50", +# 1:"etc", +# 2:"sv" ], +# 3:[ 0:"drwxr-xr-x 2 root root 4096 Mar 13 10:50", +# 1:"etc", +# 2:"tor" ] ] +# +# Only the leaves are present, the intermediates components are LINE or +# NODE if just before a leave +# +# [ 1:[ 1:LINE, 2:LINE, 3:LINE, 4:LINE, 5:NODE, 6:"filename" ] ] + +function list(entries, path) +{ + cmd = "cd '" path "' && exec find ." \ + " -name '*.git' -prune -o" \ + " -name 'CVS' -prune -o" \ + " -exec ls -ld {} +"; + + for (num = 0; cmd | getline; num++) { + sub(" \\.$", "", $0); + sub(" -> .*", "", $0); + infos = $0; + sub(" \\./.*", "", infos); + sub(".* \\./", "./", $0); + + entries[num"path"] = $0; + count = split($0, path_v, "/"); + for (i = 2; i < count; i++) + entries[num":"i] = LINE; + + entries[num":"count] = NODE; + entries[num":"1] = infos " "; + entries[num"name"] = path_v[count]; + } + close(cmd); + + return num - 1; +} + +# Transform entries into a tree by replacing some LINE by VOID when needed. +# The tree is walked from the bottom to the top, and column by column +# toward the right until an empty column is met. + +function tree(entries, num) +{ + for (i = 2; !stop; i++) { + stop = tail = 1; + for (l = num; l > 0; l--) { + if (entries[l":"i] == LINE && tail) { + entries[l":"i] = VOID; + stop = 0; + } else if (entries[l":"i] == NODE && tail) { + entries[l":"i] = TAIL; + tail = stop = 0; + } else if (!entries[l":"i]) { + tail = 1; + } + } + } +} diff --git a/pstree b/pstree @@ -0,0 +1,122 @@ +#!/usr/bin/awk -f + +# pstree implementation in awk + +# Use ps(1) to generate a list of pid, ppid and other properties with +# the command name, displayed as a tree built from the pid-ppid pairs: +# +# USER TT NI PID STAT COMMAND +# root ? 0 1 Ss runit +# josuah ? 0 22437 S |- startx +# josuah ? 0 22451 S | `- xinit +# root tty7 0 22452 Rsl+ | |- Xorg +# josuah ? 0 22457 S | `- dwm +# josuah ? 0 24882 S `- runsvdir +# josuah ? 0 24884 S |- runsv +# josuah ? 0 24887 S | |- svlogd +# josuah ? 0 24890 S | `- ratox +# josuah ? 0 24885 S `- runsv +# josuah ? 0 24405 S |- tor +# josuah ? 0 24889 S `- svlogd + +BEGIN { + LINE = "| "; + NODE = "|- "; + TAIL = "`- "; + VOID = " "; + + list(entries); + NUM = 1; fill(entries, 1, 0); + tree(entries, NUM); + + for (i = 1; i < NUM; i++) { + printf("%s", entries[i":info"]); + for (j = 1; entries[i":"j] != ""; j++) + printf("%s", entries[i":"j]); + printf("%s\n", entries[i":comm"]); + } +} + +# Build a relational database in <entries> from the output of ps: The +# parent pid (ppid) -> pid pairs are used to accumulate a list of child +# pid (serialized into a csv: ",234,532,454") later used for building +# the tree. +# +# For each pid, "info" and "comm" are saved as well. + +function list(entries) +{ + opt = "-o ppid,user,tty,pid,stat,comm" + cmd = "exec ps -ax " opt " 2>/dev/null"; + if (!(cmd | getline)) { + cmd = "exec ps " opt + cmd | getline; + } + sub(" *[^ ]+", ""); + print $0; + + for (num = 0; cmd | getline; num++) { + ppid = $1; pid = $4; + entries[ppid"cpid"] = entries[ppid"cpid"] "," pid; + sub(" *[^ ]+", ""); + sub(" *[^ ]+ + *[^ ]+ + *[^ ]+ + *[^ ]+ +", "&\t"); + split($0, info, "\t"); + entries[pid"info"] = info[1]; + entries[pid"comm"] = info[2]; + } + close(cmd); + + return num - 1; +} + +# Using the informations from the child pid in entries, build the absolute +# path from PID 1 to each pid: +# +# [ 1:[ 1:"1" ], +# 2:[ 1:"1", 2:"456" ], +# 3:[ 1:"1", 2:"456", 3:"1623" ], +# 4:[ 1:"1", 2:"456", 3:"1721" ] ] +# +# With also ":info" and ":comm" for every row. +# +# Only the leaves are present, the intermediates components are LINE or +# NODE if just before a leave +# +# [ 1:[ 1:LINE, 2:LINE, 3:LINE, 4:LINE, 5:NODE, 6:"filename" ] ] + +function fill(entries, pid, lvl) +{ + for (j = 0; j < lvl; j++) + entries[NUM":"j] = LINE; + entries[NUM":"lvl] = NODE; + entries[NUM":comm"] = entries[pid"comm"]; + entries[NUM":info"] = entries[pid"info"]; + NUM++; + while (sub("[^,]*,", "", entries[pid"cpid"])) { + cpid = entries[pid"cpid"]; + sub(",.*", "", cpid); + fill(entries, cpid, lvl + 1); + } +} + +# Transform entries into a tree by replacing some LINE by VOID when needed. +# The tree is walked from the bottom to the top, and column by column +# toward the right until an empty column is met. + +function tree(entries, num) +{ + for (j = 0; !stop; j++) { + stop = tail = 1; + for (i = num; i > 0; i--) { + if (entries[i":"j] == LINE && tail) { + entries[i":"j] = VOID; + stop = 0; + } else if (entries[i":"j] == NODE && tail) { + entries[i":"j] = TAIL; + tail = stop = 0; + } else if (!entries[i":"j]) { + tail = 1; + } + } + } +} diff --git a/tree b/tree @@ -0,0 +1,76 @@ +#!/usr/bin/awk -f + +# convert a list of paths into a tree + +BEGIN { + LINE = "| "; + NODE = "|- "; + TAIL = "`- "; + VOID = " "; + + num = list(entries); + tree(entries, num); + display(entries, num); +} + +# Get a recursive list of all entries into entries[] with entries[i:j] +# holding the component j of the path i, and 0 has all the -l details, +# then return the number of entries in entries[]. +# +# [ 1:[ 1:"etc" ], +# 2:[ 1:"etc", 2:"sv" ], +# 3:[ 1:"etc", 2:"tor" ] ] +# +# Only the leaves are present, the intermediates components are LINE or +# NODE if just before a leave +# +# [ 1:[ 1:LINE, 2:LINE, 3:LINE, 4:LINE, 5:NODE, 6:"filename" ], +# 2:[ 1:LINE, 2:LINE, 3:LINE, 4:NODE, 5:"filename" ] ] + +function list(entries) +{ + for (num = 0; getline; num++) { + sub("^/", "", $0); + sub("/$", "", $0); + count = split($0, nodelist, "/"); + for (i = 1; i < count; i++) + entries[num":"i] = LINE; + entries[num":"count] = NODE; + entries[num"name"] = nodelist[count]; + } + + return num - 1; +} + +# Transform entries into a tree by replacing some LINE by VOID when needed. +# The tree is walked from the bottom to the top, and column by column +# toward the right until an empty column is met which stops the algorithm. + +function tree(entries, num) +{ + for (i = 1; !stop; i++) { + stop = tail = 1; + for (l = num; l > 0; l--) { + if (entries[l":"i] == LINE && tail) { + entries[l":"i] = VOID; + stop = 0; + } else if (entries[l":"i] == NODE && tail) { + entries[l":"i] = TAIL; + tail = stop = 0; + } else if (!entries[l":"i]) { + tail = 1; + } + } + } +} + +# Print all entries line by line. + +function display(entries, num) +{ + for (l = 1; l <= num; l++) { + for (i = 1; entries[l":"i] != ""; i++) + printf("%s", entries[l":"i]); + printf("%s\n", entries[l"name"]); + } +}