mkcd: The missing shell shortcut

It seems like you often cd to a new directory. How often?

I have analyzed my fish shell history on a Linux machine where it spans from 2019 to 2025 and has just over 100K entries. If you have seen a fish history file, it looks like a subset of YAML:

- cmd: add-apt-repository ppa:zfs-native/stable
  when: 1342217584
- cmd: nvim dir.sha256
  when: 1614189938
  paths:
    - dir.sha256

However, it is not valid YAML. With this in mind, I wrote a script to analyze history line-by-line using Python’s helpful fileinput module.

#! /usr/bin/env python3

import fileinput

mkdir = 0
cd_after_mkdir = 0
after_mkdir = None

for line in fileinput.input(errors="surrogateescape"):
    args = line.split()  # Ignore quoting.

    if args[:2] != ["-", "cmd:"]:
        continue

    match args[2:]:
        case ["mkdir", path, *_] | ["sudo", "mkdir", path, *_]:
            path = path.rstrip("/")

            mkdir += 1
            after_mkdir = path
            continue

        case ["cd", path, *_]:
            path = path.rstrip("/")

            if path == after_mkdir:
                cd_after_mkdir += 1

        case _:
            pass

    after_mkdir = None

print(f"{mkdir = }\n{cd_after_mkdir = }")

You can download the script and try it on your history. Here is what I get on my machine:

> ./analyze.py ~/.local/share/fish/fish_history
mkdir = 1244
cd_after_mkdir = 213

213 ÷ 1244 × 100% ≈ 17% of mkdir commands are immediately followed by changing to the new directory. This is for my user account; for root, I have mkdir = 30 and cd_after_mkdir = 3, respectively. The numbers are approximate. The script ignores argument quoting, and my shell history covers time after I replaced mkdir followed by cd. Still, this seems like a lot. Why is there no standard shortcut to perform mkdir followed by cd? It doesn’t seem any prominent shell includes one. By contrast, ll for ls -l and la for ls -la are standard in fish.

I know I didn’t invent mkcd and only adopted it years after reading the first Internet comment that described it. This leads me to suspect the friction isn’t obvious. You realize the standard workflow is tiresome after you start using mkcd. (This means you adopt mkcd at your peril.)

Where does mkcd come from? Multiple discovery is likely because the core idea is so simple. I have searched Hacker News with the official Algolia search and Reddit and textfiles.com using DuckDuckGo and Google. The earliest instances I found were a January 2008 comment by HN user dreish and an April 2010 post “mkcd” by Jack Mottram on the Tumblr blog One Thing Well. The dreish comment uses mkdir -p, but Jack Mottram only replaced mkdir with mkdir -p in May 2010 follow-up “mkcd improved” after a message from a reader, suggesting he didn’t borrow from the HN comment. Searching Usenet Archives finds a linux.debian.user.german post from 2003 by Robert Michel asking how to implement mkcd as a Bash alias. Other discussions that match “mkcd” on Usenet Archives are about burning optical media.

After seeing the recommendation for mkcd enough times, in 2024 I decided to try it. I implemented it for fish and quickly became a fan. Over a year later, I can definitely recommend it. To try it yourself, you can install mkcd.fish to your fish functions directory (likely ~/.config/fish/functions/).

# From https://dbohdan.com/mkcd
# License: MIT
# https://dbohdan.mit-license.org/@2025/license.txt

function mkcd --argument name --description "Create a directory and 'cd' to it"
    if test (count $argv) -ne 1
        printf 'usage: mkcd name\n' >&2
        return 2
    end

    mkdir -p $name
    cd $name
end