~/sd is my
directory. It looks like this:
$ tree ~/sd /Users/ian/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
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 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 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:
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
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
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
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.
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