Mike Higginbottom

A Digital Garden - frequent growth but a bit weedy in the back corner

One Less Thing To Remember

Bit of background cos every good story needs a tension building pre-amble. When I’m writing stuff for this site I do it in Markdown rather than hand-cutting HTML like a savage or using one of those fancy Latte fuelled web design/hosting site ‘solutions’ that all the Millennials seem to be into (actually Millennials are getting quite old now aren’t they so maybe I need to re-focus my old-fart-get-off-my-lawn vendetta at a younger demographic).

For me, it’s a nice balance between control, flexibility and simplicity.

I’ve been running all my content through a little make build script that uses pandoc to convert the Markdown .md files to HTML. It puts the HTML files and any assets they link to into a build folder that gets synced up to my web server. Easy. Nice.

Whenever I make a change I just cd into the Markdown source folder and run make. But I figured I may as well chuck that functionality into my crontab so cron can take care of that for me every night once I’m away dreaming about whisky and dancing girls.

Now, cos I’m not very smart, my first completely unthinking attempt was 0 0 * * * make /home/mike/publish/web-site. This did not work: make: Nothing to be done for '/home/mike/publish/web-site'.. In my defence, I always just use a simple call to make from my current working directory but this kind of nonsense is only to be expected when we make assumptions and just operate on auto-pilot.

Now, much as I am deeply on-board with the idea of nothing to be done, when it’s somebody else engaging with the idea, I find it a little irksome, especially when there is, in fact, something to be done. So, time to dig in. Heavy sigh.

man make makes it clear that I was asking it to create /home/mike/publish/web-site as its target. Not what I want to do.

According to man make, the -C option will do what I want: Change to directory dir before reading the makefiles or doing anything else. So let’s test that from the command line: make -C /home/mike/publish/web-site. That’s better. Chuck it in the crontab as 0 0 * * * make -C /home/mike/publish/web-site and we’re all done.

Except, cos I’m a good boy and try to think through my errors so I don’t keep making the same ones, I got to thinking about how I could have avoided the problem in the first place.

That solution seemed quite specific. Specifically, the -C option was specific to make. More generally, what I was trying to do, in general, was run make in a specific folder. More generally still, run any command in any specific folder. Running cd and then running the command is the obvious and general solution.

So cd /home/mike/publish/web-site and then make. But I’m not quite that stupid. I’m aware of ‘things to think about 101’ when doing stuff like this.

[Lemma](https://en.wikipedia.org/wiki/Lemma_(mathematics). For example, you can’t just write a bash script to cd into a folder, run that script and then expect to be in that folder when it exits. No, no, no. The script will execute in a sub-shell with it’s own idea of what the current working directory is. Try it out:

pwd
echo "pwd; mkdir test; cd test; pwd" > "cd_test.sh"
chmod +x "cd_test.sh"
./cd_test.sh
pwd

Are you where you thought you’d be?

Anyway, back to the story.

I’m gonna do cd and then make. The standard approach (well my standard approach at least) is to join commands in bash with a semi-colon; so I’d go for cd /home/mike/publish/web-site; make. But I thought I’d stop assuming and look into it.

It turns out that joining commands with a semi-colon is not usually the smart thing to do because, if the first command fails for some reason, the second command will execute regardless. For example, if you’re in your home directory and you do cd some/path/contaiining/junk; rm -rf . you’re gonna have a bad day if you really meant to type containing rather than contaiining. Say goodbye to all your photos.

The better approach is to use &&. As in cd /home/mike/publish/web-site && make. This will only run make if the cd command was successful.

What’s the point of this story?

Prefer a general solution.

The -C option to make works fine but it’s another thing to remember. Using the && approach will work for any commands I want to chain together.