The Tilde Tragedy

27 April 2024 #ruby #linux #bash

Anyone familiar with bash1 knows about tilde expansion: in shell scripts and from the terminal, the tilde character is automatically replaced with the value of the $HOME variable, which points to the current user’s home directory. That means that

$ cd ~

is automatically expanded to

$ cd /home/caleb

which can be a very convenient shortcut!

In Ruby

Sometime in 20152, I had switched my computer over to Debian only a few months prior and I was just getting into programming with Ruby. I don’t remember exactly what I was trying to accomplish that day, but I had a script that was checking for the existence of a directory under my home folder and creating it if it was missing3:

Dir.mkdir('~/foo/bar') unless Dir.exist?('~/foo/bar')

Of course, the problem here is that Ruby, unlike Bash, doesn’t inherently support tilde expansion. Instead, you have to explicitly call something like File.expand_path() to handle the expansion. In retrospect this seems obvious, but to a young programmer I’m sure you can see why I expected this to “just work” here.

The first time I ran this script, it correctly detected the directory didn’t exist and went ahead and created it. But instead of creating the directory under my home folder, it created it right inside of the project directory I was currently working in… with the directory being named the literal ~.

And this is the point where I screwed up big time. I fixed my script, and then tried to get rid of that weird tilde folder inside my project directory, like so:

$ rm -rf ~

The command took a few seconds to run, which I thought was strange at first… until the realization hit me. I quickly spammed Ctrl+C to cancel the command, but it had already blown away half of my home directory.

Moral of the story: trying to learn a new programming language after 2 a.m. is a bad idea. Oh, and make backups.

  1. I originally had this as “shell scripting” here, but I realized that I rarely use the old-school sh shell and don’t remember if it supports tilde expansion or not. Exercise for the reader: try finding the answer via Google. All of my results were just SO posts on how tilde expansion works in bash. (I eventually just asked Anthropic’s Claude LLM, who handily told me tilde expansion was one of the many new features bash introduced over sh. Big, if true!) 

  2. For context, I would’ve been in 8th on 9th grade here, so hopefully that excuses what follows :) 

  3. Actually, since we’re creating nested directories I was probably using FileUtils::mkdir_p, which supports creating subdirectories (unlike the regular mkdir). Both methods behave the same as far as tilde expansion goes.