Read the Manual: cd

One of the few Unix tools that actually follows the Unix philosophy! Mostly, anyway.

People interested in learning how the command lines tools on their computer work.

This week’s Read the Manual entry is late because yesterday I wrote up my thoughts on programming language pedagogy instead. Today’s subject is the trusty cd command. How much can there be to changing directories? Not a lot, but there are still some interesting things to learn here!

There are, gloriously, zero flags for the command… if, like me, you use fish. It takes a single argument: cd [DIRECTORY]. The main interesting thing is that fish ships a wrapper function around the builtin cd” which lets you use cd - to go to the previous directory.

(As an aside: I often don’t even bother with typing cd, because in fish, you don’t have to. You just type a valid directory name and fish moves the current directory there. This is one of those things that I have still not fully internalized, though, even 5 years along!)

So about that built-in — finding the man page is a bit of an adventure in digging. If you man cd in any built-in shell on macOS, e.g. zsh, you will get the man page for BUILTIN(1) and an instruction to See the built-in command description in the appropriate shell manual page.” The obvious next move is man zsh or man bash and searching for cd. That doesn’t help in the case of zsh, because its docs are (reasonably!) broken up into other man pages; you actually need to do man zshbuiltins. It does work from man bash, though.

In bash, there are two options: -P to use the physical” directory structure and not to follow symlinks, -L to force symlinks to be followed. It also gets configuration from the CDPATH variable, which changes how cd searches” for non-absolute paths.

In zsh, there are two additional options, -q for quiet, which skips calling functions zsh lets you use for printing output when you change directories, and -s for refusing to navigate if the path includes symlinks. There are also two additional forms you can call in zsh:

  1. You can pass two values, like cd <old> <new>, to replace <old> with <new> in the current directory name, e.g. if I were in ~/dev/chriskrycho/some-nested-path and typed cd chriskrycho rust-lang, it would try to go to ~/dev/rust-lang/some-nested-path. Cool? 🤷🏻‍♂️

  2. You can pass +n or -n where n is a number and move through your directory history by n entries. I actually missed this a bit in fish early on, but fish gives the cdh command and I actually find that more useful, because remembering exact directory history is hard!

And that’s pretty much it. zsh also supports some other shenanigans using shell variables, but since I am a fish user, I… really don’t care. 😅

By far the most useful thing I learned today was how to read the manual entries for built-ins. The most useful thing I learned from the man page itself is that if you just do cd, with no argument at all, it goes to HOME. Instead of typing cd ~, you can just skip the extra characters and the extra dance with the Shift key. Neat!