May I suggest the name txtree?
(Really I just want `tree` on `s3`. There's `s3-tree` but that uses the entire bucket rather than a prefix)
Have you found any solutions for grepping on matching lines? Presumably, one could use awk, but awk takes a lot of cycles.
Somewhat unrelated: I discovered some time ago that the column command (from util-linux) can print trees of hierarchical data (up to 2 levels deep).
From the man page:
$ echo -e '1 0 A\n2 1 AA\n3 1 AB\n4 2 AAA\n5 2 AAB' | column --tree-id 1 --tree-parent 2 --tree 3
1 0 A
2 1 |-AA
4 2 | |-AAA
5 2 | `-AAB
3 1 `-AB
column(1): https://github.com/karelzak/util-linux/blob/master/text-util...One suggestion: it may help to generalize the newline as the node separator. You may already be doing this (my go is rusty) but instead of https://github.com/birchb1024/frangipanni/blob/7543b4ee15ae7... be able to override the "newline" as the node separator, like you've done with the "spacer" param.
What do you do when the same line is encountered?
The detailed examples are great too, showing different use cases and features.
Thank you very much for creating this tool and sharing it.
```
<img src="frangipanni.jpg" alt="A Tree" width="200" align="right">
```
May 10 03:17:06 localhost systemd: Removed slice User Slice of root.
May 10 03:17:06 localhost systemd: Stopping User Slice of root.
becomes: May 10
03:17:06 localhost systemd
: Removed slice User Slice of root
: Stopping User Slice of rootMaybe that could be resolved if it were combined with some sort of GUI / TUI that collapsed subtrees with default (maybe with child count and total anscentor count) e.g. folding by indentation in Vim / Emacs
And of course empty line was "ditto". Except this wasted paper and was later replaced with "...".
tree --fromfile
e.g. echo a/b1 a/b2/c | xargs -n1 | tree --fromfile
.
└── a
├── b1
└── b2
└── c
2 directories, 2 filesYet, this project is cool enough that I’m not even disappointed.
I always thought it was weird that "do one thing and one thing well" stopped short of dealing with tree representations on the commandline.
So it fits well with the UNIX ethos of a small tool doing one thing well, but not so much the concept of pipelines, which is closely related.
Obviously not this tool’s fault.
$ find /etc/network | ./frangi.tl
etc:
network:
if-post-down.d:
wireless-tools wpasupplicant avahi-daemon
if-down.d:
resolvconf wpasupplicant avahi-autoipd
interfaces.d interfaces if-pre-up.d:
wireless-tools wpasupplicant ethtool
if-up.d:
ntpdate wpasupplicant 000resolvconf openssh-server ethtool avahi-autoipd slrn avahi-daemon
$ find /etc/network | ./frangi-cheat.tl
/etc/network
/if-post-down.d
/wireless-tools
/wpasupplicant
/avahi-daemon
/if-down.d
/resolvconf
/wpasupplicant
/avahi-autoipd
/interfaces.d
/interfaces
/if-pre-up.d
/wireless-tools
/wpasupplicant
/ethtool
/if-up.d
/ntpdate
/wpasupplicant
/000resolvconf
/openssh-server
/ethtool
/avahi-autoipd
/slrn
/avahi-daemon
$ cat frangi-cheat.tl
#!/usr/bin/env txr
(let (old-path)
(whilet ((line (get-line)))
(whenlet ((path (tok #/[^\/]*/ line))
(canon `@{path "/"}`)
(pos (mismatch path old-path)))
(let ((cpos (max 0 (+ pos -1 [sum [path 0..pos] len]))))
(put-line `@{"" cpos}@{canon [cpos..:]}`))
(set old-path path))))
$ cat frangi.tl
#!/usr/bin/env txr
(defstruct (node name) list-builder
name
(:method equal (me) me.name)
(:method ensure-child (me child-name)
(let ((children me.(get)))
(or (find child-name me.(get))
(let ((new-child (new (node child-name))))
me.(add new-child)
new-child))))
(:method print (me stream : pretty-p)
(let* ((old-im (set-indent-mode stream indent-code))
(old-id (get-indent stream))
(children me.(get))
(is-bottom (none children .(get))))
(unwind-protect
(cond
(children
(put-line `@{me.name}:` stream)
(set-indent stream (+ old-id 4))
[mapdo (op print @1 stream) children]
(when is-bottom
(put-char #\newline stream)))
(t (put-string `@{me.name} `) stream))
(set-indent-mode stream old-im)
(set-indent stream old-id)))))
(let ((supernode (new (node :root))))
(whilet ((line (get-line)))
(let ((path (tok #/[^\/]+/ line))
(node supernode))
(each ((comp path))
(set node node.(ensure-child comp)))))
(each ((top-child supernode.(get)))
(pprinl top-child))) $ find /etc/network | ./frangi-cheat
/etc/network
/if-post-down.d
/wireless-tools
/wpasupplicant
/avahi-daemon
/if-down.d
/resolvconf
/wpasupplicant
/avahi-autoipd
/interfaces.d
/interfaces
/if-pre-up.d
/wireless-tools
/wpasupplicant
/ethtool
/if-up.d
/ntpdate
/wpasupplicant
/000resolvconf
/openssh-server
/ethtool
/avahi-autoipd
/slrn
/avahi-daemon
$ cat frangi-cheat.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char old_line[FILENAME_MAX] = "", line[FILENAME_MAX];
while (fgets(line, sizeof line, stdin)) {
char *p = line, *o = old_line, *nl = strchr(line, '\n');
if (nl)
*nl = 0;
while (*p && *o) {
char *op = p;
if (*o == '/' && *p == '/')
o++, p++;
size_t lp = strcspn(p, "/");
size_t lo = strcspn(o, "/");
if (lp == lo && !strncmp(p, o, lp)) {
p += lp;
o += lp;
printf("%*s", (int) (p - op), "");
continue;
}
p = op;
break;
}
puts(p);
strcpy(old_line, line);
}
return feof(stdin) ? EXIT_SUCCESS : EXIT_FAILURE;
}
Note: yes, we could swap pointers between two buffers instead of strcpy.- swap pointers to flip buffers instead of strcpy
- handle corner case of directory printed after contents (find -depth) by avoiding printing nothing but spaces, or nothing but spaces followed by a slash
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
typedef char buf_t[FILENAME_MAX];
buf_t buf[2] = { "" };
buf_t *pline = &buf[0], *line = &buf[1];
while (fgets(*line, sizeof *line, stdin)) {
buf_t *tmp;
char *l = *line, *p = *pline, *nl = strchr(l, '\n');
if (nl)
*nl = 0;
while (*l && *p) {
char *op = l;
if (*p == '/' && *l == '/')
p++, l++;
size_t lp = strcspn(l, "/");
size_t lo = strcspn(p, "/");
if (lp == lo && !strncmp(l, p, lp)) {
l += lp;
p += lp;
continue;
}
l = op;
break;
}
if (l[0] && (l[1] || l[0] != '/'))
printf("%*s%s\n", (int) (l - *line), "", l);
else
puts(*line);
tmp = pline, pline = line, line = tmp;
}
return feof(stdin) ? EXIT_SUCCESS : EXIT_FAILURE;
}I am a heavy user for `find <> | xargs grep` -- this makes my life so much sweeter. Thank you @birchb!