Configs Shell navigation

Getting around the shell: autocd, CDPATH and history search

autocd: type a directory name to enter it

With autocd on, typing a directory name cd’s into it — no cd prefix. Sounds lazy until you spend a day in it and then try working without it.

zsh · ~/.zshrc
setopt autocd

WHERE: ~/.zshrc — reload with source ~/.zshrc.

Bash gets the same behavior plus typo tolerance with two lines in ~/.bashrc (reload with source ~/.bashrc):

bash · ~/.bashrc
shopt -s autocd
shopt -s cdspell

cdpath: jump to project directories from anywhere

Add parent directories to cdpath and the shell finds destinations for you: from ~/code, cd myproject works from anywhere — no more cd ../../whatever/src. Ordering matters; the first match wins.

zsh · ~/.zshrc
cdpath=(.. ~ ~/code)

WHERE: ~/.zshrc — reload with source ~/.zshrc.

Bash equivalent for ~/.bashrc (reload with source ~/.bashrc):

bash · ~/.bashrc
CDPATH=".:$HOME/code"

Directories in cdpath (zsh) or CDPATH (bash) are searched when you cd to a name that doesn’t start with /, ./ or ../. With cdpath=(.. ~ ~/code), cd myproject jumps to ~/code/myproject from anywhere, and .. makes sibling directories reachable by name. The first match wins. zsh always checks the current directory first. bash doesn’t: start CDPATH with . (CDPATH=".:$HOME/code") or cd src may go to ~/code/src instead of ./src. When a CDPATH match is used, the shell prints the new path. Don’t export CDPATH, because it changes how cd behaves inside scripts.

Prefix history search on the arrow keys

This binds the up and down arrows to search your history for commands that start with what you’ve already typed. Type ssh, press up, and you only step through commands that start with ssh.

(If the arrows don’t respond, your terminal may send different codes. Run cat -v, press the arrow keys, and bind whatever it prints. zsh’s history-search-backward and history-search-forward widgets match on the first word only, not anywhere in the command. Matching anywhere needs a plugin such as zsh-history-substring-search.)

zsh · ~/.zshrc
autoload -Uz up-line-or-beginning-search down-line-or-beginning-search
zle -N up-line-or-beginning-search
zle -N down-line-or-beginning-search
bindkey '^[[A' up-line-or-beginning-search
bindkey '^[[B' down-line-or-beginning-search

WHERE: ~/.zshrc — reload with source ~/.zshrc, then open a new terminal.

Listing and making directories

Two small additions that work the same in bash and zsh: short aliases for ls, and a function that makes a directory and moves into it.

ls aliases: ll, la, l

One flag away from a better file listing: -l for the long format, -h for human-readable sizes, -a to stop hiding dotfiles. The third alias is a compromise: compact columns without the noise. Note macOS’s BSD ls doesn’t support --group-directories-first — if you’re on Linux, append it to ll.

bash or zsh
alias ll='ls -lah'
alias la='ls -lA'
alias l='ls -CF'

WHERE: ~/.zshrc or ~/.bashrc — reload with source ~/.zshrc (or source ~/.bashrc), or just open a new terminal.

For eza, a modern replacement for ls, see the eza tutorial.

mcd: make a directory and cd into it

You make a directory and then immediately cd into it. You always do. This shell function does both, and mkdir -p means it also works for nesting several levels at once.

bash or zsh
mcd() { mkdir -p "$1" && cd "$1"; }

WHERE: ~/.zshrc or ~/.bashrc — reload with source ~/.zshrc (or source ~/.bashrc). Function, not alias — aliases can’t take arguments.