Inspecting Symlink with readlink

There are a few ways to know that a file is a symlink. Here’s one I learned today. All my dotfiles are symlinks because I store them outside of the root directory. Here’s a conventional way to inspect a symlink: ls -l ~/.zshrc lrwxr-xr-x@ 1 jake staff 37 Jul 21 17:28 /Users/jake/.zshrc -> /Users/jake/code/dotfiles/./.zshrc How do we know it’s a symlink? The l at the beginning of the permissions list and the arrow -> are two clues. ...

August 19, 2026

Ripgrep files with matches

I use Ripgrep as my command-line search tool. Something I often want is to return matching filenames only, instead of Ripgrep’s rich colored output, so I can pipe them to xargs. Here’s that flag: rg -l The -l flag is short for the --files-with-matches flag. As an example, today I used it to delete all drafts from a blog project. rg -l "draft" src/content/posts/ | xargs rm See man rg for more.

August 11, 2026

Unalias an Alias

Sometimes I want to iterate on an alias. You can unalias an alias like this: unalias aliasname This is particularly useful when changing an alias to a function. When you change this: alias up="cd .." To this: up() { # Alternative implementation } And source your config, you’ll likely see this (Zsh example): .zshrc: defining function based on alias `up' .zshrc: parse error near `()' Unaliasing is an elegant path forward.

July 1, 2026

Concatenate Non-Printing Characters

I’ve been writing some non-printing characters to a file. But when I concatenate, it appears empty. cat log.txt # Nothing here 🥺 cat those non-printing characters with -v: cat -v log.txt jjjj:wq^M% See man cat for these details: -v Display non-printing characters so they are visible. Control characters print as ‘^X’ for control-X; the delete character (octal 0177) prints as ‘^?’. Non-ASCII characters (with the high bit set) are printed as ‘M-’ (for meta) followed by the character for the low 7 bits.

June 30, 2026

Prettier in Fenced Code Blocks

Prettier formats code in fenced code blocks! When I type three backticks and then a code, Prettier evaluates the code in the block and tries to format it per my global .prettierrc. I produce a lot of technical writing in markdown. I’ve often wondered if my fenced code blocks are valid, since I sometimes type them by hand. With Prettier, as long as I add a language identifier (e.g. typescript), that language is supported and configured for Prettier autoformatting, it will run on the block. ...

June 29, 2026

Vim Scratchpad Part 2

Today, I’d like to dive deeper into a part of my practice: using a persisted text file for jotting things down. In this post, I’ll explain the ‘why’ behind this technique, and provide an updated version of it. You can read the post I’m following up on here. Why Use a Scratchpad? Why use this technique? Here are a few reasons. I’m a note-taker. The military trains soldiers to always have “something to write on, and something to write with.” When I see somebody in a meeting not taking notes, I wonder if they’re paying attention and how they’re going to remember key details. ...

October 26, 2022

Vim Scratchpad

Today I’d like to share a small part of my practice: using a persisted scratchpad text file for jotting things down. When coding, often I’ll need to save a piece of data or type something out. This could be the identifier of a record, or a list of steps my pair and I think we need to take to fix a problem. Instead of creating a new file each time, I keep a scratchpad in my root directory, named ~/buffer. I’ve mapped Vim to open it from normal mode with <leader> g: ...

August 25, 2022

Tmux Application Startup Script

My development environment depends on several processes running. Here’s how I’ve scripted this setup. Whenever I boot up, I need at least these processes running: Sidekiq (jobs) Rails (API) Webpack (frontend) Docker (containers) Here’s how I’ve scripted it: #!/bin/bash tmux new-window -n sidekiq tmux send-keys -t sidekiq 'sidekiq' Enter tmux new-window -n rails tmux send-keys -t rails 'rails s' Enter tmux new-window -n webpack tmux send-keys -t webpack 'bin/webpack' Enter tmux new-window -n docker tmux send-keys -t docker 'bin/docker' Enter open http://host.docker.internal:3000/ This starts each process in its own named Tmux window, then opens the application in my browser. That last step is a losing race condition with the other processes, which are still booting, but I just wait a few seconds and refresh the browser tab. ...

July 28, 2022

Spell Checking with Vim: Tutorial and Best Practices

I write each post for this blog in Vim. Writing in the terminal makes me feel like a programmer, even when I’m not specifically programming. In this post, I’ll share how I spellcheck in Vim. Enable Spelling Vim’s spelling help page is extensive, and can be viewed at: :help spell It suggests enabling spelling like this: :setlocal spell spelllang=en_us When you to this, you’ll see words that Vim considers misspelled in red. ...

June 15, 2022

Solved! How to Exit Vim "Ex" Mode

How does one exit Vim “Ex” mode? But first… how did you even get into “Ex” mode? Probably by accidentally typing Q in normal mode: *Q* *mode-Ex* *Ex-mode* *Ex* *EX* *E501* Q Switch to "Ex" mode. This is a bit like typing ":" commands one after another, except: - You don't have to keep pressing ":". - The screen doesn't get updated after each command. - There is no normal command-line editing. - Mappings and abbreviations are not used. If this is true you probably missed the initial instructions: ...

April 6, 2022