
Linux command: cd
Every time you move around a Linux system, you use cd. You type it to step into a project, to climb back out, and to jump across a server before you edit a config file or read a log. It feels like the simplest command there is: pick a folder, go there. Yet cd is not even a real program, and understanding why teaches you something deep about how Unix works.
1. The Basics
The job of cd is to change your current working directory: the folder your shell is "standing in" right now. Almost every other command works relative to that spot. When you type ls, cat notes.txt, or ./build.sh, the shell looks for those files starting from your current directory. cd is how you move that starting point.
Two ideas make cd special. First, the current directory is not a global setting for the whole machine. Every process has its own current directory, quietly inherited from the process that started it. Your shell has one, and cd changes the shell's copy. Second, because of that, cd cannot be an ordinary command that lives on disk. It has to be built into the shell itself. Section 6 explains exactly why.
The command you type more than almost any other, and the one most people never really think about. Behind those two letters sits the reason Unix commands are split between "programs" and "builtins".
This article starts with the simplest possible move and builds up to the directory stack, logical versus physical paths, and the surprising fact that cd is a shell builtin. By the end you will understand not just how to move around, but why moving around works the way it does.
Back to topThe right mental model: your shell holds a single invisible pointer into the filesystem tree.
cdmoves that pointer. It does not open anything, copy anything, or change any file. It only changes where "here" is.
2. Where the Name Comes From
The name cd is short for change directory.
cd = Change Directory
Like most early Unix commands, it was made short on purpose. Early Unix was typed on slow teletype terminals that printed each character onto paper, so short names saved both time and ink. That is why so many core commands are two letters: ls (list), cp (copy), mv (move), rm (remove), and cd (change directory).
Once a name is in everyone's muscle memory, there is no reason to change it. Fifty years later, cd is still cd on every Unix-like system in the world.
3. A Short History
The idea of a "current working directory" was one of the innovations of the original Unix at Bell Labs in the early 1970s. Before hierarchical filesystems became normal, the notion that you could "be somewhere" in a tree of directories and refer to files relative to that spot was a genuinely new idea. The chdir system call, which cd uses under the hood, has been part of Unix since those first editions.
| Era | Milestone |
|---|---|
| Early 1970s | Unix introduces the hierarchical filesystem and the chdir system call |
| 1979 (Bourne shell) | cd is a shell builtin; $HOME is the default target |
| 1980s (C shell) | pushd, popd, and the directory stack appear |
| Today | Bash, Zsh, and every POSIX shell ship cd, cd -, and CDPATH |
One important note about versions. Because cd is part of the shell, its exact features depend on which shell you run, not on your Linux distribution. This article describes Bash, the default shell on most Linux systems. Zsh and other shells behave almost identically for everyday use, with a few extra conveniences of their own.
4. Simple Use Cases
4.1 The Simplest Possible Move
Give cd a path and it takes you there. In the examples below, the line that starts with $ is what you type; pwd ("print working directory") confirms where you landed.
$ cd /var/log
$ pwd
/var/log
Notice that cd prints nothing when it succeeds. Silence means success. This is the Unix habit of "no news is good news": a command only speaks up when something goes wrong.
4.2 Absolute and Relative Paths
You can point cd at a directory in two ways. An absolute path starts with a slash and describes the location from the root of the filesystem. A relative path does not start with a slash and is understood from where you are now.
$ cd /etc/nginx # absolute: always the same place
$ cd sites-enabled # relative: a folder inside where I already am
Relative paths are what make cd quick. If you are already in /etc/nginx, you type cd sites-enabled instead of the full path.
4.3 Going Up: ..
Every directory contains two special entries: . means "this directory" and .. means "the parent directory". You use .. constantly to climb back up.
$ cd .. # up one level
$ cd ../.. # up two levels
$ cd ../sibling # up one, then down into a neighbour folder
4.4 Going Home: cd With No Path
Type cd on its own, with nothing after it, and it takes you to your home directory. This is the value of the $HOME variable, usually /home/yourname.
$ cd
$ pwd
/home/peter
The tilde ~ is a shorthand for the same place, and it also works as part of a longer path:
$ cd ~ # home, same as bare cd
$ cd ~/Documents # the Documents folder inside home
$ cd ~peter # the home directory of the user "peter"
4.5 Jumping Back: cd -
This is the one that feels like magic once you know it. cd - takes you back to the directory you were in just before the last cd. It toggles between two places, like the "last channel" button on a remote.
$ pwd
/home/peter/project
$ cd /etc/nginx
$ cd - # jump back
/home/peter/project
$ cd - # and back again
/etc/nginx
Notice that cd - also prints the directory it moved to. It is the one form of cd that is not silent, because it is convenient to see where you landed. Behind the scenes, the shell remembers your previous directory in a variable called $OLDPWD, and cd - simply jumps to it.
5. Moderate Use Cases
5.1 A Shortcut Search Path: CDPATH
By default, a relative cd only looks inside your current directory. The CDPATH variable changes that. It is a list of "base" directories, separated by colons, that cd will also search when you give it a relative name. It works like PATH does for programs, but for folders.
$ export CDPATH=~/projects:~/work
$ cd website # not here, but found in ~/projects/website
/home/peter/projects/website
Now you can type cd website from anywhere and land in ~/projects/website, without typing the full path. When cd uses CDPATH to find the target, it prints the resulting path so you can see where you actually went.
A useful trick, with one trap: always put
.(the current directory) somewhere inCDPATH, usually first. Otherwise a relativecdmay quietly prefer a folder from your list over one that is right next to you.
5.2 Tab Completion
You rarely type a whole directory name. Press Tab after a few letters and the shell completes it for you; press Tab twice to see all the matches.
$ cd /et<Tab> # completes to /etc/
$ cd Doc<Tab> # completes to Documents/
Tab completion is part of the shell, not of cd itself, but the two are used together so often that they feel like one feature. It is the single biggest reason experienced users move so fast.
5.3 Directory Names in Variables: cdable_vars
Bash has an optional convenience called cdable_vars. When you switch it on, cd will treat a plain word as the name of a variable if no such directory exists.
$ shopt -s cdable_vars
$ export proj=~/projects/website
$ cd proj # no folder called "proj", so use the variable
/home/peter/projects/website
It is a small feature, but it shows a theme that runs through this article: cd quietly tries several strategies to turn the word you typed into a real location.
5.4 When cd Fails
Unlike most commands so far, cd can fail, and it tells you why. The two everyday errors are a path that does not exist and a directory you are not allowed to enter.
$ cd /no/such/place
bash: cd: /no/such/place: No such file or directory
$ cd /root
bash: cd: /root: Permission denied
To enter a directory you need execute permission on it (the x bit you saw in ls -l). For a directory, "execute" does not mean running it; it means the right to step into it. This is why a folder can be readable but still refuse your cd.
6. Advanced Use Cases
6.1 Why cd Must Be a Shell Builtin
Here is the fact that makes cd genuinely interesting. Run these two commands:
$ type cd
cd is a shell builtin
$ which cd
$ # prints nothing: there is no program called cd
There is no file /bin/cd or /usr/bin/cd to run. cd is built into the shell. The reason is one of the most important rules in Unix: a child process cannot change its parent's current directory.
When you run a normal program like ls, the shell starts it as a separate child process. That child gets its own copy of the current directory. If cd were a normal program, it would start as a child, change its own current directory, and then exit, and your shell (the parent) would not have moved an inch. The change would vanish with the child.
shell (your process) current dir: /home/peter
|
+-- runs a program gets a COPY of the current dir
changes its own dir
exits the copy is thrown away
|
shell (your process) current dir: STILL /home/peter
The only way to change the shell's own directory is to run the code inside the shell process, not in a child. That is exactly what a builtin is: a command the shell runs itself. So cd has to be a builtin. The same is true for anything that must change the shell's own state, such as export and umask.
Under the hood, the shell does the actual move through a single kernel system call named chdir() ("change directory"). The current working directory is not a shell invention; it is a property the kernel stores for every process. When you type cd /var/log, the shell calls chdir("/var/log"), and the kernel updates the shell process's own current directory. Because a child process inherits a copy of that directory but can never reach back into its parent, the builtin is the only place the call can usefully happen.
6.2 The Directory Stack: pushd, popd, dirs
Where cd - remembers one previous directory, the directory stack remembers a whole pile of them. pushd ("push directory") moves you to a new directory and saves your current one on top of a stack. popd ("pop directory") removes the top entry and takes you back to it. dirs shows the stack.
$ cd /usr
$ pushd /etc # go to /etc, remember /usr
/etc /usr
$ pushd /var # go to /var, remember /etc and /usr
/var /etc /usr
$ dirs -v # show the stack, numbered
0 /var
1 /etc
2 /usr
$ popd # drop /var, go back to /etc
/etc /usr
This is how you take a quick detour without losing your place. You pushd into another directory, do a small job, and popd straight back to where you were. For a deep task with many jumps, the stack beats trying to remember paths by hand.
6.3 Logical Versus Physical: -L and -P
Symbolic links make one directory appear inside another. This raises a subtle question: when you cd through a symlink and then type cd .., where should "up" take you? Back the way you came, or up the real folder on disk?
By default, cd is logical (the -L option, short for logical): it remembers the path you typed, symlinks and all. The -P option (short for physical) makes cd resolve every symlink first, so you sit in the real directory on disk.
$ ln -s /var/www/html site # "site" is a link to /var/www/html
$ cd site
$ pwd
/home/peter/site # logical: the path you followed
$ pwd -P
/var/www/html # physical: the real location
$ cd .. # logical: back to /home/peter
$ cd -P site && cd .. # physical: up from /var/www/html to /var/www
Most of the time the logical default is what you want, because it matches how you got there. Reach for cd -P when you care about the true location on disk, for example in a script that must not be confused by a symlinked path.
7. Something Most Users Do Not Know
7.1 There Really Is a /usr/bin/cd (On Some Systems)
We just said cd cannot be an external program. That is true for changing your shell. Yet the POSIX standard still requires a cd utility to exist as a file, and some Unix systems (notably macOS) really do ship a /usr/bin/cd. What could it possibly do?
Almost nothing useful. If you run it, it starts as a child process, changes that child's directory, and immediately exits. Your shell does not move. The file exists only so that standards-compliant scripts and tools that look for a real command can find one. On most Linux systems the file is not even present, because the builtin is all anyone ever needs. It is a small reminder that a "command" and a "program on disk" are not the same thing.
7.2 cd Inside a Script Does Not Follow You Out
The same builtin rule surprises people writing scripts. When you run a script, it launches in its own shell process. Any cd inside it changes that process's directory, not yours. When the script ends, you are exactly where you started.
$ cat goto.sh
#!/bin/bash
cd /var/log # changes the SCRIPT's directory only
$ ./goto.sh
$ pwd
/home/peter # unchanged: the script ran in a child shell
If you genuinely want a script to move your shell, you must run it with source goto.sh (or the shorthand . goto.sh), which runs the lines in your current shell instead of a child. This is also why people write a small shell function, not a script, when they want a custom "jump to my project" command.
7.3 $PWD, $OLDPWD, and the Deleted Directory
The shell keeps your current directory in the variable $PWD and the previous one in $OLDPWD (the variable that powers cd -). One odd situation is worth knowing: if another process deletes the directory you are sitting in, you are now standing in a folder that no longer has a name on disk.
$ cd /tmp/work
$ rm -rf /tmp/work # done from another terminal
$ ls
ls: cannot open directory '.': No such file or directory
The cure is simple: cd somewhere that still exists, for example cd ~ or cd ... It is a good demonstration that "where you are" is a live link to a real directory, not just a string.
8. Best Practices
- Learn
cd -today. Toggling between two directories withcd -saves more keystrokes than almost any other trick. It is the first thing to make automatic. - Use
pushdandpopdfor detours. When you need to pop into another folder and come straight back, the directory stack keeps your place for you. - Lean on Tab completion. Type a few letters and press Tab. It is faster and it prevents typos in long paths.
- Set
CDPATHfor folders you visit constantly, and always include.in the list so a nearby folder still wins. - Use
source, not execution, when a script must move your shell. A plain./script.shchanges only the script's own directory. - Reach for the documentation. Because
cdis a builtin, its manual is inside the shell, not a separate page.
$ help cd # the built-in help for cd (Bash)
$ help pushd # and for the directory stack
$ man bash # the full shell manual, with a SHELL BUILTINS section
Note that man cd usually says "No manual entry", precisely because cd is not a standalone program. Use help cd instead.
9. Common Mistakes
9.1 Three Common Myths
| Myth | Reality |
|---|---|
"cd is a program like ls." |
It is a shell builtin. There is no /bin/cd to run, and there cannot be a useful one. |
"A cd inside my script changes my shell." |
It changes only the script's own child process. Use source to affect your shell. |
"cd .. always goes to the real parent folder." |
By default it follows the path you took. Through a symlink, use cd -P for the real parent. |
9.2 Other Traps to Avoid
- Confusing "cannot enter" with "does not exist". A
Permission deniederror means the directory is there but you lack the execute bit on it, not that the path is wrong. - Trying to
cdinto a file. If you pointcdat a regular file instead of a directory, you getbash: cd: notes.txt: Not a directory. It is a different error from "No such file", and it usually means you meant a command likecatorless, notcd. - Forgetting
.inCDPATH. Without it, a relativecdmay silently jump to a folder from your list instead of the one right beside you. - Expecting
cdto print the path. On success it stays silent. Onlycd -and aCDPATHmatch print where you landed. - Sitting in a deleted directory. If commands suddenly fail with "No such file or directory" for
., you are in a folder that was removed. Justcdsomewhere that still exists. - Assuming spaces are fine unquoted. To enter
My Documents, quote it:cd "My Documents"orcd My\ Documents. Otherwise the shell reads two arguments.
10. Summary
The cd command looks trivial, but it is a doorway into how Unix processes and the filesystem really work.
cdmeans "change directory". It moves your shell's current working directory, the spot every other command works from.- It cannot be an ordinary program, because a child process cannot change its parent's directory. That is why
cdis a shell builtin. - Bare
cdgoes home,cd ..goes up,cd -jumps back to the previous directory, and~is shorthand for home. CDPATHgives relativecda search path;cdable_varslets a variable name stand in for a folder.pushd,popd, anddirsmanage a stack of directories for taking detours without losing your place.-L(logical, the default) follows the path you typed;-P(physical) resolves symlinks to the real location on disk.- A
cdinside a script only moves that script; usesourceto move your own shell. - The help lives in the shell:
help cd, notman cd.
This is the quick reference worth keeping:
cd DIR go to a directory
cd go to your home directory
cd ~/x go to folder x inside home
cd .. go up one level
cd - jump back to the previous directory
pushd DIR go there and save the old spot on the stack
popd return to the last saved spot
dirs -v show the directory stack, numbered
cd -P DIR enter the real directory, resolving symlinks
help cd the built-in manual
Small commands like cd hide a surprising amount of how Linux is built. If your servers behave in ways that are hard to explain, or you want a setup that is easier to run day to day, it often pays to look closely at the fundamentals. That is exactly the kind of work I enjoy helping with.


Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.


