251130: zsh: cd
Source: Dev.to
Goal
This dive took 6.5 hours
The goal of this document is to dive deep into the following commands:
cd /
cd -
cd
cd ..
Target Audience
Intended for users with a basic understanding of Linux command‑line operations who want to deepen their knowledge of directory‑navigation commands, with simple copy‑paste examples.
Backgrounds
| Command | Description |
|---|---|
cd / | Navigates to the root directory |
cd .. | Navigates to the parent directory |
cd or cd ~ | Navigates to the home directory |
cd - | Navigates to the previous directory (acts like a “Back” button) |
Dive in
How to check the source code of cd command?
type cd
# cd is a shell builtin
cd is implemented directly inside the shell (e.g., bash, zsh).
How do we know which shell we are using?
echo $SHELL # /bin/zsh
# or
echo $0 # -zsh
Let’s quickly check the version
zsh --version
# zsh 5.9 (arm64-apple-darwin24.0)
Dive into the source code of cd’s bin_cd command in zsh
The official repository is https://github.com/zsh-users/zsh.
Key functions:
cd_get_dest()– initial argument processingcd_do_chdir()– performs the actualchdir()callcd_new_pwd()– ancillary processing after a successful directory change
Restricted shell check
if (isset(RESTRICTED)) {
zwarnnam(nam, "restricted");
return 1;
}
zwarnnam formats warning messages. In restricted mode, cd may be blocked.
Example
zsh -r # start a restricted shell
cd .. # → zsh: cd: restricted
cd with chasing symbolic links
chasinglinks = OPT_ISSET(ops,'P') || (isset(CHASELINKS) && !OPT_ISSET(ops,'L'));
chasinglinks is true when:
-Poption is specified, or- the
CHASELINKSoption is enabled, unless overridden by-L.
Setup for testing
tmp_dir=$(date +%y%m%d_%H%M%S_test)
mkdir "$tmp_dir" && cd "$tmp_dir"
mkdir physical_path
ln -s physical_path symbolic_link
Check the layout
ls -al
# total 0
# drwxr-xr-x 4 user staff 128 ... .
# drwxr-x---+ 73 user staff 2336 ... ..
# drwxr-xr-x 3 user staff 96 ... physical_path
# lrwxr-xr-x 1 user staff 13 ... symbolic_link -> physical_path
Tests
# Default (no -P, no CHASE_LINKS)
cd symbolic_link
pwd # /path/to/tmp_dir/symbolic_link
# With -P (physical path)
cd ..
cd -P symbolic_link
pwd # /path/to/tmp_dir/physical_path
# Enable CHASE_LINKS globally
cd ..
setopt CHASE_LINKS
cd symbolic_link
pwd # /path/to/tmp_dir/physical_path
# Override with -L (logical path)
cd ..
cd -L symbolic_link
pwd # /path/to/tmp_dir/symbolic_link
setopt
The setopt builtin is implemented in Src/options.c.
How to check the options set in your shell?
/* With no arguments or options, display options. */
if (!*args) {
scanhashtable(optiontab, 1, 0, OPT_ALIAS, optiontab->printnode, !isun);
return 0;
}
setopt
# chaselinks
# combiningchars
# interactive
# …
How to check what options are not yet enabled?
unsetopt
# noaliases
# aliasfuncdef
# allexport
# …
Signal handling during cd execution
queue_signals(); /* block interrupt-like signals while changing directory */
Blocking signals ensures that the critical operation of changing directories completes without interruption.
Directory stack handling
zpushnode(dirstack, ztrdup(pwd));
pwd holds the current working directory before the change. The directory stack can be inspected with:
dirs -v
# 0 ~/Workspaces
# 1 ~/Workspaces/oss
Dive into cd_get_dest()
cd_get_dest() determines the destination directory based on the arguments passed to cd:
- No arguments → returns the home directory (
$HOME). -→ returns the previous directory from the directory stack (OLDPWD).- Specific path → returns the supplied path (after processing options such as
-P/-L).
It returns NULL on error (e.g., when the previous directory is not set).
End of document.