~/sd is my script directory. It looks like this:

$ tree ~/sd
├── blog
│   ├── preview
│   └── publish
├── book
│   ├── open
│   ├── pdf
│   ├── progress
│   └── typeset
├── cat
├── dim
│   └── visualize
├── edit
├── git
│   └── ugh
├── help
├── new
├── nix
│   ├── diff
│   ├── info
│   └── sync
├── tmux
│   ├── init
│   └── restore
└── which

sd is a command on my PATH. It dispatches its arguments to my script directory.

$ sd blog publish

Will run the script ~/sd/blog/publish.

This sounds like a dumb way to save myself having to type a few characters. Which it is. But it’s also slightly more than that:

sd has nice tab completion. That’s the only real difference between sd and ~/sd: those little descriptions of what the commands do. In case you don’t run JavaScript, it looks something like this:

$ sd nix <TAB>
diff  -- prints what will happen if you run sync
info  -- <package> prints package description
sync  -- make user environment match ~/dotfiles/user.nix

It’s not much. But it’s nice.

Those descriptions come from comments in the command files themselves, or from separate command.help files (in case there is a lot to say, or the command is not a shell script).

For example, in the demo above, I run sd help nix sync, which ends up running cat ~/sd/nix/sync.help. The first line is all that ends up in the completion menu, but the rest of the text is there in case I forget how a command works.

a boring story about sd

I wrote sd one afternoon when I couldn’t find a script I wanted in my ~/bin. I knew it was there – and I knew what it did – but I couldn’t remember what I’d named it.

I had close to a hundred different scripts in ~/bin, all with names that made perfect sense when I added them: visualize, transplant, deploy, etc.

I decided enough was enough, so I added a little structure, and sd was born.

It’s much easier to remember what commands do when they’re namespaced like this. And it’s much easier to remember how to use them when you write their usage down. I’ve used sd ever since, and I don’t think I could go back to a flat ~/bin.

I only have a few sd commands on my laptop, because I don’t find myself writing a lot of complicated scripts at home. But sd was written for work, where I had dozens of helpers all neatly categorized by project or tool or domain. It was good.

do you want to use sd?

It’s not really a thing. It’s more of an idea. You can implement it yourself in one sitting, if you want.

But of course you don’t want to figure out how to write your own shell completion. Shell completion is some arcane nonsense. You want me to have already done it. But here’s the thing: I only wrote zsh completions because I only ever use zsh interactively.

I’ve sometimes thought about rewriting sd as something other than a pile of shell and publishing it and publicizing it and adding bash support and what have you. But you know what? I probably won’t ever do that. But maybe someone else will, if they like the idea enough.

You’re welcome to use my implementation, though, if you use zsh. It works on macOS and Linux, and it has a GitHub repo of its very own.

Oh, one last thing: sd only looks for executables, so you can add non-executable helpers that you can source from multiple scripts in the same directory. When sd invokes a command, $0 is the absolute path to the command, so you can use dirname "$0" to get at your helpers. Like you’d expect.

how has sd affected you

Being able to type sd new foo command instead of vim ~/bin/command, typing the shebang, trying to run it, realizing I forgot to make it executable, running it again… it’s made my life slightly better. And because it’s so easy to save snippets for later, I find that I’m much more likely to do it – and a lot less likely to find myself combing through ctrl-r a few months later.

Otherwise, you know, it’s not lifechanging. It won’t help you to appreciate the smaller beauties all around you. You’ll still wake up feeling groggy. Lately I’ve been using it to make user-friendly wrappers around nix-env as part of my series How to Learn Nix, which has been nice.

One day I might rewrite it as a real executable and add some nice features like easier command line parsing for scripts, but sd is like a 95/20 situation. It’s pretty good even in its neglected, janky state. As long as you’re using zsh.

But don’t take my word for it.