Shell Navigation 101
There's more than just 'cd'

Navigating the shell is an indispensable skill.
While GUIs might be more intuitive in some ways than the command line, they lack the speed and raw power a shell offers.
Therefore, efficient shell navigation that goes beyond just cd
goes a long way.
Table of Contents
This short guide will recap the basics before going beyond them, looking at more sophisticated navigation commands.
The Basics of Shell Navigation
Let’s start with the essentials, focusing on probably the most familiar commands.
Going Places (cd)
The cd
command is a shell built-in that, who would have guessed, changes the current working directory.
It’s likely one of the first commands you ever learned and is ingrained into muscle memory, but it has more to offer than meets the eye.
It supports both absolute and relative paths:
# ABSOLUTE
$ cd /usr/local/bin
# RELATIVE
$ cd ../logs
The double-dots (..
) represent the parent directory.
There’s also the single-dot (.
) to represent the current working directory, but we don’t need to include it.
The following calls are equal:
$ cd ./logs
# IS EQUAL TO
$ cd logs
Without any path after cd
, the current working directory is changed to the content of the HOME
shell variable, the home directory.
The first underutilized and quite handy feature of the cd
is using a dash (-
) in place of a path, which returns to the previous directory:
# NAVIGATE TO HOME DIRECTORY
$ cd
# NAVIGATE FAR AWAY
$ cd /usr/local/bin
# JUMP BACK TO PREVIOS DIRECTORy (HOME)
$ cd -
And, finally, the most apparent problem with cd
is not escaping a path correctly:
$ cd "My Documents"
Where am I? (pwd)
The pwd
command outputs the absolute path of the current working directory.
It’s an invaluable tool when working deep within nested directories or getting the current directory in scripts, etc.
$ pwd
/home/ben/articles
It has two options:
-L
/--logical
: Uses the value from $PWD even if it contains symlinks-P
/--physical
: Avoid symlinks in the output
By default, -P
is assumed.
As pwd
is also a shell built-in, the actual implementation might depend on the shell you’re using.
But the overall functionality won’t differ.
Beyond the Basics: The Directory Stack
Navigating complex projects often requires frequent directory switching.
Instead of relying solely on cd
in a repetitive fashion, we can use directory stacks instead.
What is the Directory Stack?
Directory stacks are, well, a stack structure, meaning they follow the last in, first out principle. It’s a list where we can “push” directories on top and “pop” them off to the previous one as needed.
The pushd
command stores the current working directory and, navigates to the new one, and outputs the stack:
$ cd
$ pushd /user/local/bin
/usr/local/bin ~
The first listed directory is the current directory, and the previous one, our home in the form of ~
(tilde), is the next one on the stack.
Removing the top directory from the stack and navigating to the previous one is done with the popd
command:
$ cd
$ pushd /etc
/etc ~
$ pushd /var/logs
/var/logs /etc ~
# GOING BACK TO /etc
$ popd
/etc ~
Managing the Directory Stack
The dirs
command complements the other directory stack management utilities.
At its core, it displays the current directory stack, a list of directories we navigated using pushd
and popd
.
By default, the current working directory is always the topmost entry in the stack:
$ dirs
~
The output format is controllable via multiple options:
-l
: Expands~
(tilde) to the actual path-p
: Prints every stack entry on a separate line-c
: Clear the stack-v
: Also prints one per line but prefixes the index
The last option (printing with index) is useful for pushd
and popd
, as they allow to modify the stack:
$ dirs -lv
0 /boot
1 /var/log
2 /etc
3 /home/ben
# ROTATE FORWARD
$ pushd +2
/var/log /etc ~ /boot
By using +2
as the option for push,
the second entry of the stack was moved to the top and became the current working directory.
The same is possible in reverse, by using -
(minus) and the position from the bottom of the stack.
These calls do not add a new directory but reorder the whole stack.
It’s also possible to remove specific entries from the stack by using the same principle with popd
:
$ dirs -lv
0 /boot
1 /var/log
2 /etc
3 /home/ben
# ROTATE FORWARD
$ popd +2
/boot /etc ~
And, of course, the opposite direction is done by using -
(minus).
As the directory is removed, the current working directory hasn’t been changed.
Where Are My Things: CDPATH
CDPATH
is a shell variable that defines search paths for the cd
command.
Instead of typing full paths, you can quickly jump to directories in CDPATH
.
Settings CDPATH
The simplest way to modify it is exporting it in the shell’s rc-file, for example, the ~/.bashrc
:
CDPATH=.:~:/mnt/data
This particular CDPATH
looks in the following locations in order:
.
: The current directory~
: The home directory/mnt/data
: A specific folder
Now, we can cd
to any folder in one of the paths wherever we are.
For example, if I have a folder called code
in my home directory, cd code
works from any location.
Unless there’s a code
directory in the current working directory, which has precedence.
Be aware that quoting the value didn’t work for me. I’m not sure if this is a shell-specific thing, and I didn’t find any information about it.
Best Practices and Caveats
Modifying CDPATH
sounds intriguing at first, but we have to be aware of a few things:
- Always include
.
(dot) to prioritize the current directory - Don’t overdo it to avoid unexpected matches
- Don’t export the variable
The last advice is that it is imperative to not pollute the environment and only affect interactive shells.
This is especially important if cd
is used in shell scripts.
To be absolutely sure, calling unset CDPATH
might be a good idea to start from a clean slate.
Another way to circumvent CDPATH
is to use absolute paths, even for seemingly relative ones:
# USES CDPATH
$ cd code
# IGNORES CDPATH
$ cd ./code
However, this is a mere band-aid, not a sensible solution to the problem.
To be honest, I’d recommend leaving CDPATH
alone, as it might break a lot of things quite subtly.
Maybe not on your machine, but when you share scripts with others.
As an alternative, I suggest using aliases for directories you frequently visit.
alias ce='cd ~/code/elipse'
This approach’s main advantage is choosing an alias name to your liking, independently of the actual directory name.
Conclusion
The commands dirs
, pushd
, and popd
are handy tools for managing directory stacks, especially when paired with their options.
By mastering these commands and their nuances, you can significantly improve your efficiency in navigating the shell.
Whether you’re working on large projects, switching between directories for system administration, or just trying to keep your terminal workspace organized, these tools will save you time and effort.