Chapter 4. Cruising the Filesystem
In the movie The Adventures of Buckaroo Banzai Across the 8th Dimension, a classic cult comedy from 1984, the swashbuckling title character offers the following Zen-like words of wisdom: “Remember, no matter where you go…there you are.” Buckaroo could very well have been talking about the Linux filesystem:
$ cd /usr/share/lib/etc/bin No matter where you go... $ pwd /usr/share/lib/etc/bin ...there you are.
It’s also the case that wherever you are in the Linux filesystem—your current directory—you will eventually go somewhere else (to another directory). The faster and more efficiently you can perform this navigation, the more productive you can be.
The techniques in this chapter will help you navigate the filesystem more quickly with less typing. They look deceptively simple but have enormous bang for the buck, with small learning curves and big payoffs. These techniques fall into two broad categories:
-
Moving quickly to a specific directory
-
Returning rapidly to a directory you’ve visited before
For a quick refresher on Linux directories, see Appendix A.
If you use a shell other than bash
, see Appendix B for
additional notes.
Visiting Specific Directories Efficiently
If you ask 10 Linux experts what is the most tedious aspect of the command line, seven of them will say, “Typing long directory paths.”1 After all, if your work files are in /home/smith/Work/Projects/Apps/Neutron-Star/src/include, your financial documents are in /home/smith/Finances/Bank/Checking/Statements, and your videos are in /data/Arts/Video/Collection, it’s no fun to retype these paths over and over. In this section, you’ll learn techniques to navigate to a given directory efficiently.
Jump to Your Home Directory
Let’s begin with the basics. No matter where you go in the
filesystem, you can return to your home directory by running cd
with
no arguments:
$ pwd /etc Start somewhere else $ cd Run cd with no arguments... $ pwd /home/smith ...and you're home again
To jump to subdirectories within your home directory from anywhere in
the filesystem, refer to your home directory with a shorthand rather
than an absolute path such as /home/smith. One shorthand is the shell
variable HOME
:
$ cd $HOME/Work
$ cd ~/Work
Both $HOME
and ~
are expressions expanded by the shell, a fact
that you can verify by echoing them to stdout:
$ echo $HOME ~ /home/smith /home/smith
The tilde can also refer to another user’s home directory if you place it immediately in front of their username:
$ echo ~jones /home/jones
Move Faster with Tab Completion
When you’re entering cd
commands, save typing by pressing the Tab
key to produce directory names automatically. As a demonstration,
visit a directory that contains subdirectories, such as /usr:
$ cd /usr $ ls bin games include lib local sbin share src
Suppose you want to visit the subdirectory share. Type sha
and
press the Tab key once:
$ cd sha<Tab>
The shell completes the directory name for you:
$ cd share/
This handy shortcut is called tab completion. It works immediately
when the text that you’ve typed matches a single directory name.
When the text matches multiple directory names, your shell needs
more information to complete the desired name. Suppose you had typed
only s
and pressed Tab:
$ cd s<Tab>
The shell cannot complete the name share (yet) because
other directory names begin with s
too: sbin and src. Press
Tab a second time and the shell prints all possible completions to
guide you:
$ cd s<Tab><Tab> sbin/ share/ src/
and waits for your next action. To resolve the ambiguity, type another
character, h
, and press Tab once:
$ cd sh<Tab>
The shell completes the name of the directory for you, from sh to share:
$ cd share/
In general, press Tab once to perform as much completion as possible, or press twice to print all possible completions. The more characters you type, the less ambiguity and the better the match.
Tab completion is great for speeding up navigation. Instead of typing a lengthy path like /home/smith/Projects/Web/src/include, type as little as you want and keep pressing the Tab key. You’ll get the hang of it quickly with practice.
Tab Completion Varies by Program
Tab completion isn’t just for cd
commands. It works for most
commands, though its behavior may differ. When the command is
cd
, the Tab key completes directory names. For other commands that
operate on files, such as cat
, grep
, and sort
, tab completion
expands filenames too. If the command is ssh
(secure shell), it
completes hostnames. If the command is chown
(change the owner of a
file), it completes usernames. You can even create your own completion
rules for speed, as we’ll see in Example 4-1. Also see man bash
and
read its topic “programmable completion.”
Hop to Frequently Visited Directories Using Aliases or Variables
If you visit a faraway directory frequently, such as
/home/smith/Work/Projects/Web/src/include, create an alias that
performs the cd
operation:
# In a shell configuration file:
alias
work
=
"cd
$HOME
/Work/Projects/Web/src/include"
Simply run the alias anytime to reach your destination:
$ work $ pwd /home/smith/Work/Projects/Web/src/include
Alternatively, create a variable to hold the directory path:
$ work=$HOME/Work/Projects/Web/src/include $ cd $work $ pwd /home/smith/Work/Projects/Web/src/include $ ls $work/css Use the variable in other ways main.css mobile.css
Edit Frequently Edited Files with an Alias
Sometimes, the reason for visiting a directory frequently is to edit a
particular file. If that’s the case, consider defining an alias to
edit that file by absolute path without changing directory. The
following alias definition lets you edit $HOME/.bashrc, no matter
where you are in the filesystem, by running rcedit
. No cd
is required:
# Place in a shell configuration file and source it:
alias
rcedit
=
'$EDITOR $HOME/.bashrc'
If you regularly visit lots of directories with long paths, you can create aliases or variables for each of them. This approach has some disadvantages, however:
-
It’s hard to remember all those aliases/variables.
-
You might accidentally create an alias with the same name as an existing command, causing a conflict.
An alternative is to create a shell function like the one in
Example 4-1, which I’ve named qcd
(“quick cd”). This function accepts
a string key as an argument, such as work
or recipes
, and runs
cd
to a selected directory path.
Example 4-1. A function for cd
-ing to faraway directories
# Define the qcd function
qcd
()
{
# Accept 1 argument that's a string key, and perform a different
# "cd" operation for each key.
case
"
$1
"
in
work
)
cd
$HOME
/Work/Projects/Web/src/include
;;
recipes
)
cd
$HOME
/Family/Cooking/Recipes
;;
video
)
cd
/data/Arts/Video/Collection
;;
beatles
)
cd
$HOME
/Music/mp3/Artists/B/Beatles
;;
*
)
# The supplied argument was not one of the supported keys
echo
"qcd: unknown key '
$1
'"
return
1
;;
esac
# Helpfully print the current directory name to indicate where you are
pwd
}
# Set up tab completion
complete
-W
"work recipes video beatles"
qcd
Store the function in a shell configuration file such as
$HOME/.bashrc (see “Environments and Initialization Files, the Short Version”), source it, and it’s
ready to run. Type qcd
followed by one of the supported keys to
quickly visit the associated directory:
$ qcd beatles /home/smith/Music/mp3/Artists/B/Beatles
As a bonus, the script’s final line runs the command complete
, a
shell builtin that sets up customized tab completion for qcd
, so it
completes the four supported keys. Now you don’t have to remember
qcd
’s arguments! Just type qcd
followed by a space and press the
Tab key twice, and the shell will print all the keys for your
reference, and you can complete any of them in the usual way:
$ qcd <Tab><Tab> beatles recipes video work $ qcd v<Tab><Enter> Completes 'v' to 'video' /data/Arts/Video/Collection
Make a Big Filesystem Feel Smaller with CDPATH
The qcd
function handles only the directories that you specify. The
shell provides a more general cd
-ing solution without this
shortcoming, called a cd search path. This shell feature transformed
how I navigate the Linux filesystem.
Suppose you have an important subdirectory that you visit often, named Photos. It’s located at /home/smith/Family/Memories/Photos. As you cruise around the filesystem, anytime you want to get to the Photos directory, you may have to type a long path, such as:
$ cd ~/Family/Memories/Photos
Wouldn’t it be great if you could shorten this path to just Photos, no matter where you are in the filesystem, and reach your subdirectory?
$ cd Photos
Normally, this command would fail:
bash: cd: Photos: No such file or directory
unless you happen to be in the correct parent directory
(~/Family/Memories) or some other directory with a Photos
subdirectory by coincidence. Well, with a little setup, you can
instruct cd
to search for your Photos subdirectory in locations
other than your current directory. The search is lightning fast and
looks only in parent directories that you specify. For example, you
could instruct cd
to search $HOME/Family/Memories in addition to
the current directory. Then, when you type cd Photos
from elsewhere
in the filesystem, cd
will succeed:
$ pwd /etc $ cd Photos /home/smith/Family/Memories/Photos
A cd search path works like your command search path, $PATH
, but
instead of finding commands, it finds subdirectories. Configure it
with the shell variable CDPATH
, which has the same format as PATH
:
a list of directories separated by colons.
If your CDPATH
consists of these four directories, for example:
$HOME:$HOME/Projects:$HOME/Family/Memories:/usr/local
and you type:
$ cd Photos
then cd
will check the existence of the following directories in
order, until it finds one or it fails entirely:
-
Photos in the current directory
-
$HOME/Photos
-
$HOME/Projects/Photos
-
$HOME/Family/Memories/Photos
-
/usr/local/Photos
In this case, cd
succeeds on its fourth try and changes directory to
$HOME/Family/Memories/Photos. If two directories in $CDPATH
have a
subdirectory named Photos, the earlier parent wins.
Note
Ordinarily, a successful cd
prints no output. When cd
locates a
directory using your CDPATH
, however, it prints the absolute path on
stdout to inform you of your new current directory:
$ CDPATH=/usr Set a CDPATH $ cd /tmp No output: CDPATH wasn't consulted $ cd bin cd consults CDPATH... /usr/bin ...and prints the new working directory
Fill CDPATH
with your most important or frequently used parent
directories, and you can cd
into any of their subdirectories from
anywhere in the filesystem, no matter how deep they are, without
typing most of the path. Trust me, this is awesome, and the following
case study should prove it.
Organize Your Home Directory for Fast Navigation
Let’s use CDPATH
to simplify the way you navigate your home
directory. With a little configuration, you can make many directories
within your home directory easily accessible with minimal typing, no
matter where you are in the filesystem. This technique works best if
your home directory is well organized with at least two levels of
subdirectories. Figure 4-1 shows an example of a well-organized
directory layout.
The trick is to set up your CDPATH
to include, in order:
-
$HOME
-
Your choice of subdirectories of
$HOME
-
The relative path for a parent directory, indicated by two dots (
..
)
By including $HOME
, you can jump immediately to any of its
subdirectories (Family, Finances, Linux, Music, and Work)
from anywhere else in the filesystem without typing a leading path:
$ pwd /etc Begin outside your home directory $ cd Work /home/smith/Work $ cd Family/School You jumped 1 level below $HOME /home/smith/Family/School
By including subdirectories of $HOME
in your CDPATH
, you can jump into
their
subdirectories in one shot:
$ pwd /etc Anywhere outside your home directory $ cd School /home/smith/Family/School You jumped 2 levels below $HOME
All the directories in your CDPATH
so far are absolute paths in
$HOME
and its subdirectories. By including the relative path
..
however, you empower new cd
behavior in every directory. No matter
where you are in the filesystem, you can jump to any
sibling
directory (../sibling
) by name without typing the two dots,
because cd
will search your current parent. For example, if you’re in
/usr/bin and want to move to /usr/lib, all you need is cd lib
:
$ pwd /usr/bin Your current directory $ ls .. bin include lib src Your siblings $ cd lib /usr/lib You jumped to a sibling
Or, if you’re a programmer working on code that has subdirectories src, include, and docs:
$ pwd /usr/src/myproject $ ls docs include src
you can jump between the subdirectories concisely:
$ cd docs Change your current directory $ cd include /usr/src/myproject/include You jumped to a sibling $ cd src /usr/src/myproject/src Again
A CDPATH
for the tree in Figure 4-1 might contain six items:
your home directory, four of its subdirectories, and the relative path
for a parent directory:
# Place in a shell configuration file and source it:
export
CDPATH
=
$HOME
:$HOME
/Work:$HOME
/Family:$HOME
/Linux:$HOME
/Music:..
After sourcing the configuration file, you can cd
to a large number
of important directories without typing long directory paths, just
short directory names. Hooray!
This technique works best if all subdirectories beneath the
CDPATH
directories have unique names. If you have duplicate names,
such as $HOME/Music and $HOME/Linux/Music, you might not get the
behavior you want. The command cd Music
will always check $HOME
before $HOME/Linux and consequently will not locate
$HOME/Linux/Music by search.
To check for duplicate subdirectory names in the first two levels of
$HOME
, try this brash one-liner. It lists all
subdirectories and sub-subdirectories of $HOME
, isolates the
sub-subdirectory names with cut
, sorts the list, and counts
occurrences with uniq
:
$ cd $ (ls -d */ && ls -d */*/ | cut -d/ -f2-) | sort | uniq -c | sort -nr | less
You may recognize this duplicate-checking technique from
“Detecting Duplicate Files”. If the output displays any counts greater
than 1, you have duplicates. I realize this command includes a few features
I haven’t covered yet. You’ll learn double ampersand (&&
) in “Technique #1: Conditional Lists”
and the parentheses
in “Technique #10: Explicit Subshells”.
Returning to Directories Efficiently
You’ve just seen how to visit a directory efficiently. Now I’ll show you how to revisit a directory quickly when you need to go back.
Toggle Between Two Directories with “cd -”
Suppose you’re working in a deep directory and you run cd
to go
somewhere else:
$ pwd /home/smith/Finances/Bank/Checking/Statements $ cd /etc
and then think, “No, wait, I want to go back to the Statements
directory where I just was.” Don’t retype the long directory
path. Just run cd
with a dash as an argument:
$ cd - /home/smith/Finances/Bank/Checking/Statements
This command returns your shell to its previous directory and helpfully prints its absolute path so you know where you are.
To jump back and forth between a pair of directories, run cd -
repeatedly. This is a time-saver when you’re doing focused work in two
directories in a single shell. There’s a catch, however: the shell
remembers just one previous directory at a time. For example, if you
are toggling between /usr/local/bin and /etc:
$ pwd /usr/local/bin $ cd /etc The shell remembers /usr/local/bin $ cd - The shell remembers /etc /usr/local/bin $ cd - The shell remembers /usr/local/bin /etc
and you run cd
without arguments to jump to your home directory:
$ cd The shell remembers /etc
the shell has now forgotten /usr/local/bin as a previous directory:
$ cd - The shell remembers your home directory /etc $ cd - The shell remembers /etc /home/smith
The next technique overcomes this limitation.
Toggle Among Many Directories with pushd and popd
The cd -
command toggles between two directories,
but what if you have three or more to keep track of? Suppose you’re
creating a local website on your Linux computer. This task often
involves four or more directories:
-
The location of live, deployed web pages, such as /var/www/html
-
The web-server configuration directory, often /etc/apache2
-
Your work directory, such as ~/Work/Projects/Web/src
Believe me, it’s tedious to keep typing:
$ cd ~/Work/Projects/Web/src $ cd /var/www/html $ cd /etc/apache2 $ cd ~/Work/Projects/Web/src $ cd /etc/ssl/certs
If you have a large, windowing display, you can ease the burden by
opening a separate shell window for each directory. But if you’re
working in a single shell (say, over an SSH connection), take
advantage of a shell feature called a directory stack. It lets you
quickly travel among multiple directories with ease, using the
built-in shell commands pushd
, popd
, and dirs
. The learning
curve is maybe 15 minutes, and the huge payoff in speed lasts a
lifetime.2
A directory stack is a list of directories that you’ve visited in the
current shell and decided to keep track of. You manipulate the stack
by performing two operations called pushing and popping. Pushing a
directory adds it to the beginning of the list, which is traditionally
called the top of the stack. Popping removes the topmost directory
from the stack.3 Initially, the stack contains only your current directory, but
you can add (push) and remove (pop) directories and rapidly cd
among
them.
Note
Every running shell maintains its own directory stack.
I’ll begin with the basic operations (pushing, popping, viewing) and then get to the good stuff.
Push a directory onto the stack
The command pushd
(short for “push directory”) does all of the
following:
-
Adds a given directory to the top of the stack
-
Performs a
cd
to that directory -
Prints the stack from top to bottom for your reference
I’ll build a directory stack of four directories, pushing them onto the stack one at a time:
$ pwd /home/smith/Work/Projects/Web/src $ pushd /var/www/html /var/www/html ~/Work/Projects/Web/src $ pushd /etc/apache2 /etc/apache2 /var/www/html ~/Work/Projects/Web/src $ pushd /etc/ssl/certs /etc/ssl/certs /etc/apache2 /var/www/html ~/Work/Projects/Web/src $ pwd /etc/ssl/certs
The shell prints the stack after each pushd
operation. The current
directory is the leftmost (top) directory.
View a directory stack
Print a shell’s directory stack with the dirs
command. It does not
modify the stack:
$ dirs /etc/ssl/certs /etc/apache2 /var/www/html ~/Work/Projects/Web/src
If you prefer to print the stack from top to bottom, use the -p
option:
$ dirs -p /etc/ssl/certs /etc/apache2 /var/www/html ~/Work/Projects/Web/src
and even pipe the output to the command nl
to number the lines from
zero onward:
$ dirs -p | nl -v0 0 /etc/ssl/certs 1 /etc/apache2 2 /var/www/html 3 ~/Work/Projects/Web/src
Even simpler, run dirs -v
to print the stack with numbered lines:
$ dirs -v 0 /etc/ssl/certs 1 /etc/apache2 2 /var/www/html 3 ~/Work/Projects/Web/src
If you prefer this top-down format, consider making an alias:
# Place in a shell configuration file and source it:
alias
dirs
=
'dirs -v'
Pop a directory from the stack
The popd
command (“pop directory”) is the reverse of pushd
. It does
all of the
following:
-
Removes one directory from the top of the stack
-
Performs a
cd
to the new top directory -
Prints the stack from top to bottom for your reference
For example, if your stack has four directories:
$ dirs /etc/ssl/certs /etc/apache2 /var/www/html ~/Work/Projects/Web/src
then repeatedly running popd
will traverse these directories from top
to bottom:
$ popd /etc/apache2 /var/www/html ~/Work/Projects/Web/src $ popd /var/www/html ~/Work/Projects/Web/src $ popd ~/Work/Projects/Web/src $ popd bash: popd: directory stack empty $ pwd ~/Work/Projects/Web/src
Swap directories on the stack
Now that you can build and empty the directory stack, let’s focus on
practical use cases. pushd
with no arguments swaps the top two
directories in the stack and
navigates to the new top directory. Let’s
jump between /etc/apache2 and your work directory several times by
simply running pushd
. See how the third directory /var/www/html
remains in the stack as the first two directories swap positions:
$ dirs /etc/apache2 ~/Work/Projects/Web/src /var/www/html $ pushd ~/Work/Projects/Web/src /etc/apache2 /var/www/html $ pushd /etc/apache2 ~/Work/Projects/Web/src /var/www/html $ pushd ~/Work/Projects/Web/src /etc/apache2 /var/www/html
Notice that pushd
behaves similarly to the cd -
command, toggling
between two directories, but it does not have the limitation of
remembering just one directory.
Turn a mistaken cd into a pushd
Suppose you are jumping among several directories with pushd
and
you accidentally run cd
instead and lose a directory:
$ dirs ~/Work/Projects/Web/src /var/www/html /etc/apache2 $ cd /etc/ssl/certs $ dirs /etc/ssl/certs /var/www/html /etc/apache2
Oops, the accidental cd
command replaced ~/Work/Projects/Web/src
in the stack with /etc/ssl/certs. But don’t worry. You can add the
missing directory back to the stack without typing its long path. Just
run pushd
twice, once with a dash argument and once without:
$ pushd - ~/Work/Projects/Web/src /etc/ssl/certs /var/www/html /etc/apache2 $ pushd /etc/ssl/certs ~/Work/Projects/Web/src /var/www/html /etc/apache2
Let’s dissect why this works:
-
The first
pushd
returns to your shell’s previous directory, ~/Work/Projects/Web/src, and pushes it onto the stack.pushd
, likecd
, accepts a dash as an argument to mean “go back to my previous directory.” -
The second
pushd
command swaps the top two directories, bringing you back to /etc/ssl/certs. The end result is that you’ve restored ~/Work/Projects/Web/src to the second position in the stack, exactly where it would have been if you hadn’t made your mistake.
This “oops, I forgot a pushd” command is useful enough that it’s worth
an alias. I call it slurp
because in my mind, it “slurps back” a
directory that I lost by mistake:
# Place in a shell configuration file and source it:
alias
slurp
=
'pushd - && pushd'
Go deeper into the stack
What if you want to cd
between directories in the stack other than
the top two? pushd
and popd
accept a positive or negative integer
argument to operate further into the stack. The command:
$ pushd +N
shifts N
directories from the top of the stack to the bottom
and then performs a cd
to the new top directory. A negative argument
(-N
) shifts directories in the opposite direction, from the
bottom to the top, before performing the cd
.4
$ dirs /etc/ssl/certs ~/Work/Projects/Web/src /var/www/html /etc/apache2 $ pushd +1 ~/Work/Projects/Web/src /var/www/html /etc/apache2 /etc/ssl/certs $ pushd +2 /etc/apache2 /etc/ssl/certs ~/Work/Projects/Web/src /var/www/html
In this manner, you can jump to any other directory in the stack with
a simple command. If your stack is long, however, it may be difficult
to judge a directory’s numeric position by eye. So, print the numeric
position of each directory with dirs -v
, as you did in
“View a directory stack”:
$ dirs -v 0 /etc/apache2 1 /etc/ssl/certs 2 ~/Work/Projects/Web/src 3 /var/www/html
To shift /var/www/html to the top of the stack (and make it your current
directory), run pushd +3
.
To jump to the directory at the bottom of the stack, run pushd -0
(dash zero):
$ dirs /etc/apache2 /etc/ssl/certs ~/Work/Projects/Web/src /var/www/html $ pushd -0 /var/www/html /etc/apache2 /etc/ssl/certs ~/Work/Projects/Web/src
You also can remove directories from the stack beyond the top
directory, using popd
with a numeric argument. The command:
$ popd +N
removes the directory in position N from the stack, counting down
from the top. A negative argument (-N
) counts up from the bottom
of the stack instead. Counting begins at zero, so popd +1
removes the second directory from the top:
$ dirs /var/www/html /etc/apache2 /etc/ssl/certs ~/Work/Projects/Web/src $ popd +1 /var/www/html /etc/ssl/certs ~/Work/Projects/Web/src $ popd +2 /var/www/html /etc/ssl/certs
Summary
All of the techniques in this chapter are easy to grasp with a bit of practice and will save you lots of time and typing. The techniques I’ve found particularly life changing are:
-
CDPATH
for rapid navigation -
pushd
andpopd
for rapid returns -
The occasional
cd -
command
1 I made this up, but it’s surely true.
2 An alternative is to open multiple virtual displays using command-line programs like screen
and tmux
, which are called terminal multiplexers. They’re more effort to learn than directory stacks but worth a look.
3 If you know stacks from computer science, a directory stack is precisely a stack of directory names.
4 Programmers may recognize these operations as rotating the stack.
Get Efficient Linux at the Command Line now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.