For some reason I like the Bourne shell (sh(1)
).
I think it has something to do with the fact that it's arcane,
it's everywhere,
and people always seem impressed when I know it.
I even have some bonafides, check it out:
- bollux, a gemini/gopher browser I wrote in bash
- mrgrctrnl, a simplish ssh tunnel-ifier
- shatom,
a feed generator in POSIX
sh(1)
andstat(1)
. - unk, a static site generator in 1,000 bytes of shell
- nef, "son of unk," an ssg in just 444 bytes
You might've heard of code golf, where hackers try to code something useful or neat in as small a space as possible. Many times, it's done in C, like the famous business card ray tracer. Sadly, I don't know C. So I code golf in shell.
Until the past week or so, the last two programs above, unk
and nef
, were my foray into code golfing.
Maybe because I'm easily distractable, or maybe because I just can't leave well
enough alone, (or more likely, because I just can't focus on work), I began to
golf nef
even more.
Let me begin by showing you the source of unk
and nef. I'll paste
them straight here because they're pretty short.
unk
In total, unk
weighs in at 982 total bytes, or just under UN
Kilobyte. I like silly names :)
unk
This is the main entry point to unk
. As in, you run this to build
a site.
#!/bin/sh
alias c=cat q=test e=echo
rm -r O;mkdir -p O
q -f L||e '`c $F`'>L
q -d S&&cp -r S O/
X(){ eval "$(e 'c<<.';c "$@";e;e .)";}
for F in I/*
do q -f "$F"&&(e $F
N="${F#I/}"
T(){ sed 1q "$F";}
B(){ sed 1d "$F";}
X L>"O/${N%.*}")
done
lht
This is my attempt at mostly writing HTML but like, less of it (Less Hyper Text).
#!/usr/bin/awk -f
function s(t,i){while(match($0,t)){if(I[ni]==i)ni-=sub(t,"</"i">")
else if(sub(t,"<"i">"))I[++ni]=i}}BEGIN{FS="\n"; RS="";ni=0}
{$0=(match($0,/^<.*>$/))?$0:"<p>"$0"</p>"
s("__","strong");s("\*","em");s("`","code"); print}
L
Finally, the default Layout for pages.
<!DOCTYPE html>
<meta charset=utf-8>
<title>$(T|sed 's/<[^>]\+>//g')</title>
$(q -f S/s.css&&e '<link rel=stylesheet href=S/s.css>'||
e '<style>body{max-width:70ch;padding:1em;margin:auto}
#toc{background:pink;padding:1em;display:block}</style>')
<h1>$(T)</h1>
$(B|./lht)
$(q "${N%.*}" = index&&(e '<ul id=toc>Pages'
for p in I/*;do q $p = $F&&continue;n="${p#I/}"
e "<li><a href='${n%.*}.htm'>$(sed 1q $p)</a></li>"
done;e '</ul>')||(e '<a id=toc href=index.htm>return</a>'))
<p id=ft>© 2019</p>
nef
nef
is much simpler. It's contained only in one file and weighs in
at 444 bytes.
#!/bin/sh
rm -r O;mkdir O;cp -r S O;alias P=echo T=sed\ q
X()(eval "$(P 'cat<<.';cat;P;P .)");[ -x H ]&&H=./H||H=H
H()(awk -F\n -vRS='' '!/^<.*>$/{$0="<p>"$0"</p>"}{print}')
[ -f L ]||P '<!DOCTYPE html><title>$(T $F)</title>
<style>body{max-width:70ch;padding:1%}</style>
<h1>$(T $F)</h1>$(sed 1d $F|X|$H)<hr>/ $(for P in I/*;do
[ $P = $F ]||(N=${P#I/};P "<a href=./${N%.*}>$(T $P)</a> ")
done)'>L;for F in I/*;do N=${F#I/};X<L>O/${N%.*};done
I can do better
nef
isn't bad... but I saw some immediate opportunities for
golfing:
- in
H
, the-vRS=''
can be shortened to just-vRS=
, saving 2 bytes. - if I don't put input files in a subdirectory (
I/
), I can save all the bytes where I refer to it, plus the bytes where I do path munging to get each file's basename ($N
). -
in the
<style>
tag, I can use other units. I opted formax-width:6in;
at first.of course, after a while I noticed that I could just remove the styling altogether.
- I don't have to include a navigation section (everything
after the
<hr>
innef
) on each page, and that saves a good amount of bytes.
uh... more stuff
I'm going to be honest: I didn't keep good track of all the changes I made. However, I did stare at this code for ages and ages and finally got it down to 140 bytes—small enough to fit in a text message! Here it is, in all its glory:
#!/bin/sh
x()(eval "$(echo 'dd<<.';awk -vRS= '!/^</{$0="<p>"$0}//';echo .)")
<l&&. ./l;<t||echo '`x<$z`'>t;for n in *.n;do x<t>${n%.n};done
This takes advantage of the following shorteners:
dd
is one byte shorter thancat
and does the same thing (more noisily)- you don't have to close the
<p>
tag [ -f FILE ]
takes up way too much space. you can just try to redirect from it using<FILE
, then branch on that exit code.
This basic script formed the basis of my site.
so what have we learned?
the main thing I learned from this exercise is that, if you properly define
your goal, you can do anything. my early versions of unk
and
nef
were just doing too much! now, I really only convert
almost-html files to html files, and shell-expand the contents afterward for
templating. oh yeah! I haven't even talked about the shell-expansion
templating thing!
... but it grows late, and I grow weary. in the process of writing this I hacked a bunch of stuff related to the site as well, like these .txt files you can easiliy read and other such things.