but what make

Thinking about this cool file: https://git.sr.ht/~akkartik/basic-build/tree/main/item/build

Basically we have a shell function older_than, which returns a truthy value if the first argument doesn’t exist or if it’s older than any of the remaining arguments. From there, you can basically write a crappy makefile; the example given is

older_than a.out x.c && {
  $CC $CFLAGS x.c
}

(The curly braces aren’t necessary but they are subshell syntax, which I think means that cd-ing from one shell won’t affect the others)

Why do I like this so much? I think I like how “explicit” it is?

In practice

I thought it’d be fun to change my website’s makefile to use a script like this. In practice shell’s abysmal array support kinda bit me in the bum

My makefile starts with basically

garden-sources := $(shell find garden -name "*.md" -type f)
garden-outs    := $(patsubst garden/%.md,out/%.html,$(garden-sources))

This is easy enough in pure shell;

export garden_sources=$(find garden -name "*.md" -type f)
export garden_outs=$(echo "$garden_sources" | sed -E 's;garden/(.+)\.md;out/\1.html;')

and you can iterate over one array at a time with for garden in $garden_sources; do ... done.

for garden in $garden_sources; do
    garden_out=...?
    older_than "$garden_out" "$garden" && {
        echo "insert pandoc command here" $garden $garden_out
    }
done

But how do I index into garden_outs? Posix SH doesn’t have associative arrays, and you can’t iterate over both in lockstep (aside from monumentally goofy O(n2)O(n^2) things like head/cut)

I could give up and use bash but let’s see how far i get with sh. What if instead we use a function to get the output name from the input, instead of materializing them all at once.

export garden_sources=$(find garden -name "*.md" -type f)
garden_src_to_dst() {
    echo "$1" | sed -E 's;garden/(.+)\.md;out/\1.html;'
}

Then we only have to iterate over one array at a time.

for garden in $garden_sources; do
    garden_out=$(garden_src_to_dst "$garden")
    older_than "$garden_out" "$garden" && {
        echo "insert pandoc command here" $garden $garden_out
    }
done

but:

$ time ./b.sh > /dev/null

real    0m0.545s
user    0m0.189s
sys     0m0.430s

Come on, really. Already hit half a second of execution time due to spawning sed a million times and haven’t even done any work yet