👩‍💻 chrismanbrown.gitlab.io

Smol Finger Client

a little plan / project browser with find and fzf

2024-09-01

The finger command was allegedly written in 1971 by some guy named Les. Its real world analogy is pointing, the act of running your finger down a directory listing or phone book, looking for a certain person or contact. It is one of, if not the very first, presence protocols for remote users. (The same way Slack, AIM, and xmpp report presence or status: available, away, etc.) You can run the finger command on a host running the finger daemon and get information over the finger protocol. (That’s a lot of finger!) In response, you get users’ time logged in, time spent idle, .plan and .project file contents, and sometimes phone number and office location.

You get somebody’s finger info remotely by running the finger command obviously. e.g. finger dozens@tilde.town. Or in lynx, lynx finger://dozens@tilde.town. Or by using a smolnet browser like Kristall or Lagrange. Or with necat: `echo “dozens” | nc tilde.town 79”

Anyway, I’m not interested in all of that. I just want to browse the .plan and .project files of some of my friends because we’ve organized a kind of accountability jam called #tilde30. Jam rules require one to update one’s .plan with some kind of goal that will be worked toward over 30 days, and also a couple of milestones toward reaching that goal. Weekly check-ins and updates go in .project.

So I just wanna see those .plans and .projects!

There are 58 users who have updated their .plan file in the last 30 days:

2>/dev/null find /home -maxdepth 2 -type f -mtime -30 -name .plan | wc -l
Explanation

The contents of the default .plan file is “This is my .plan file. There are many like it, but this one is mine.” Let’s be sure to filter those out.

2>/dev/null find /home -maxdepth 2 -type f \( -name .plan -o -name .project \) \
  -exec grep -L "This is my .plan file. There are many like it, but this one is mine." {} \+
Explanation

Let’s start by tweaking the first line: drop the -mtime flag to return all the files instead of just fresh ones. While we’re at it, include .project files in addition to .plan files: -o is the “or” flag, and we group the two conditionals with escaped round brackets: \( -name .plan -o -name .project \).

-exec executes a command on the results of the found files. The {} is a stand in for the filename. The + apppends all the found file names to the command. It must be escaped with a backslash.

grep searches all the files for the supplied string. (The default plan contents.) The -L inverts the default behavior: it returns results that DON’T match the string.

The next part is easy. We’ll sort the list by most recently updated by piping the files to ls -t via xargs.

2>/dev/null find /home -maxdepth 2 -type f \( -name .plan -o -name .project \) \
  -exec grep -L "This is my .plan file. There are many like it, but this one is mine." {} \+  \
  | xargs ls -t

Now we’ll clean up the file paths a little bit for fzf:

2>/dev/null find /home -maxdepth 2 -type f \( -name .plan -o -name .project \) \
  -exec grep -L "This is my .plan file. There are many like it, but this one is mine." {} \+ \
  | xargs ls -t \
  | sed 's#/home/##' \
  | fzf --preview='cat /home/{}'

sed just strips the /home/ off the filepath so that it looks nice. And then pipes the list of filenames into fzf.

In the preview pane, we cat the contents of the file. And that’s it! That’s the whole UI!

Everything else is just fzf keystrokes: ctrl-n and ctrl-p to scroll list items. shift-up and shift-down to scroll the preview. Start typing to fuzzy search for a specific file.

There are a couple extra things we can do to spice up the preview:

#!/usr/bin/env sh
2>/dev/null find /home -maxdepth 2 -type f \( -name .plan -o -name .project \) \
  -exec grep -L "This is my .plan file. There are many like it, but this one is mine." {} \+ \
  | xargs ls -t \
  | sed 's#/home/##' \
  | fzf \
    --preview='printf "%s: %s\n" $(date -d"$(stat /home/{} -c %y)" -I) {}; fold -sw 80 /home/{}' \
    --cycle --reverse --preview-window=75%
Explanation

Adding the ‘shebang’ #!/usr/bin/env sh on line 1 makes it possible to execute this as a script.

The preview consists of two expressions: a printf and a fold.

Save this to ~/bin/fing and chmod +x ~/bin/fing. And now you got a sort of finger browser powered by find and fzf!

Small catch though: It only works on the server!

Or does it?

I have the server listed in my ssh config:

Host server
  HostName server.example.com
  User myname
  IdentityFile ~/.ssh/id_rsa

so I can use the shorthand ssh server instead of ssh myname@server.example.com and then typing in my password.

This is convenient, and allows me to trivially run remote commands over ssh. e.g. ssh server ls.

You can’t run fzf non-interactively though. And trying to will cause a ssh error. Fortunately, we can forcefully allocate a tty with a -tt flag.

ssh server -tt ~/bin/fing

This works!

Let’s pop this into a file with a shebang, chmod +x it, and now I have a local script that runs the browser remotely!

cat<<EOF > ~/bin/local_fing && chmod +x ~/bin/local_fing
#!/usr/bin/env sh
ssh server -tt ~/bin/fing
EOF