Easily switch directories in the Linux shell

Reading Time: 8 min
Category: software

When using Linux to develop software, you often use a command line shell such as bash or zsh to access the full power of the operating system. Your project may be spread across multiple directories, causing you to switch directories often. Typing “cd ~/swdev/blog/retired-engineer.com/theme/blog” gets old pretty quickly. Below are several approaches to minimizing typing when doing CLI development.

Go to your home directory using cd

To change to your home directory quickly, simply type cd with no parameters.

Example:

~/swdev/blog/retired-engineer/themes/blog% cd
~%

You can also type cd ~. The symbol ~ is a shortcut for your home directory. When the shell encounters ~, it replaces the ~ with your home directory path (example: /home/re).

~/swdev/blog/retired-engineer/themes/blog% cd ~
~%

The shell also recognizes the . symbol as a shortcut to your current working directory. So, typing cd . behaves as follows:

~/swdev/blog/retired-engineer/themes/blog% cd .
~/swdev/blog/retired-engineer/themes/blog%

Set cd search path using the CDPATH variable

Linux shells including bash and zsh support an environment variable named CDPATH.

You are probably already familiar with the PATH variable. But what is CDPATH?

The PATH variable tells the shell which directories to search to locate programs to run. For instance, when you type the command df into the shell, the shell searches every directory in the PATH for an executable file named df. I often create a ~/bin directory in my home directory, in which I store various executable binaries and shell scripts. By placing my current directory . followed by ~/bin at the beginning of my PATH as shown below, the shell first searches my current directory followed by my personal bin directory before searching other locations:

export PATH=.:~/bin:$PATH

If this command is placed in your .zshenv file (for ZSH shell) or your .bashrc file (for the bash shell), then PATH is set as shown above each time a new shell starts (such as when you log in).

The CDPATH variable tells the shell cd (change directory) command which directories to search. The cd command searches CDPATH when you type cd followed by the name of a directory, and also when using tab completion (i.e. typing “cd” then hitting tab).

Assume you have several subdirectories in you home folder, such as:

/home/re
	/home/re/bin
	/home/re/documents
	/home/re/downloads
	/home/re/swdev
	/home/re/swdev/downloads

Add /home/re (or ~) to your CDPATH in .zshenv or .bashrc as follows:

export CDPATH=~:$CDPATH

Now, no matter what directory you are currently in, when you type cd downloads, you will go to the /home/re/downloads (that is, the ~/downloads) folder. Unless, you are in the /home/re/swdev directory, in which case you will go to the /home/re/swdev/downloads directory. Why? Because cd always searches your current working directory before searching CDPATH (in other words, there is an implicit . at the start of the CDPATH).

If you type cd then press tab (assuming you have tab completion enabled), you will be given bin, documents, downloads and swdev as completion options.

CDPATH provides a handy way to minimize typing paths while moving around your system from the command line interface (CLI). I normally set CDPATH to at minimum include my home directory as follows:

export CDPATH=~

Set shell alias

The shell alias command can be used to assign a shortcut name to a longer command. Here are several example aliases from my .zshrc:

alias df='df -h'
alias blog='cd ~/swdev/blog/retired-engineer.com'
alias post='cd ~/swdev/blog/retired-engineer.com/content/posts'
alias theme='cd ~/swdev/blog/retired-engineer.com/themes/blog'

The first line defines an alias so that when df is typed in the shell, the shell executes df -h. This technique works because when a command is entered in the shell, it first searches its list of aliases then searches the PATH environment variable. This is a handy way to redefine Linux commands to enable options that you always use.

The following three lines define aliases that use the cd command to switch to directory paths that I use to develop this blog

When I type blog, theme or post into the CLI, the shell changes directories as shown below. This is a powerful way to save typing that I use often when developing this blog!

/var/log/some/long/path% blog
~/swdev/retired-engineer.com% 

Source shell script containing cd

You may have tried creating an executable shell script in your ~/bin directory to switch directories similar to the script shown below. And it didn’t work. How could such a simple script not work?

Let’s create a file named “theme” that (tries to) switch directories:

#!/bin/bash
cd ~/swdev/blog/retired-engineer.com/themes/blog

Make the script executable (chmod +x theme), and execute it by typing `./theme’. The script executes but does not change to the specified directory. Why?

In bash/zsh, when you execute an external command or shell script (such as df) as opposed to a built-in shell command (such as alias or cd), Linux spawns a subtask from the shell to execute the command. As soon as the command/script completes, the spawned task completes as well.

This is a key concept, so let say it a different way: the shell executes built-in commands within the shell’s current context, but when executing an external command it creates a new context that is discarded when the external command exits.

So when you execute the shell script above (which is an external command), the shell spawns a new task, executes the cd command (which is a built-in command) which changes to the specified directory within the newly spawned task, then the external command completes causing the new task to exit returning you back to your original shell task – which is still in the original directory.

Linux shells have a built-in command source which execute a script in the context of the current task, rather than spawning a new task. This is the proper way to use our theme script to change directories:

~/some/directory/somewhere% source theme
~/swdev/blog/retired-engineer.com/themes/blog% 

Tangent: How can you tell whether a Linux command is built into the shell or external?

Answer: Use the built-in shell command which.

Here are some tests using the zsh shell:

~% which cd
cd: shell built-in command
~% which alias
alias: shell built-in command
~% which df
df: aliased to df -h
~% which du
/usr/bin/du
~% which source
source: shell built-in command
~% which which
which: shell built-in command

As seen above, the the du command is external and is located in /usr/bin, while df is an alias for df -h. The df command is also external – trust me (or remove the alias, type which, and prove to yourself that df is also an external command).

Cd to variable

Yet another alternative for changing directories with less typing is to set a Linux shell variable then cd to that variable. For instance:

~% xxx="/home/re/swdev/blog/retired-engineer.com/themes/blog"
~% cd $xxx
~/swdev/blog/retired-engineer.com/themes/blog% 

Note that the variable must be set to the full absolute path – setting it to “~/swdev/blog/retired-engineer.com/themes/blog” results in an error message when executing cd $xxx. Why? Because the shell doesn’t expand symbols such as ~ when they are found within an environment variable. Instead, the shell treats the contents of environment variables as literal strings that it does not process.

Tiling Window Manager

Common Linux Window Managers are GNOME, KDE, XFCE, etc. Instead of these, I use the i3 tiling window manager.

i3 allows window creation / resize / movement and even virtual screen management with very simple shortcut keys. For instance, pressing [Windows key][Screen Num] in i3 switches to virtual screen . The keyboard shortcuts quickly become second nature.

A tiling window manager does not allow windows to overlap.

With a tiling window manager, you can open multiple CLI and non-CLI windows on a single virtual screen, arrange them as you like, and quickly switch between them via keyboard shortcuts.

Below is a typical layout I use when doing blog development. I view a local instance of the blog in a web browser in the left window. I edit CSS in the top right window (CSS files located in ~/blog/retired-engineer.com/theme/blog/static/css). In the two small windows in the lower right corner, I run the Hugo build command and the Cloudflare local development command. These both watch for changes and rebuild automatically. By keeping both open and visible, I can see if a change that I made causes a build error.

i3 Tiling Window Manager for Blog Development

Bottom line is that with a tiling window manager, I work simultaneously in multiple directories spread across multiple virtual screens and quickly switch between them with keyboard shortcuts such as [Windows key][left], [Windows key][down] or [Windows key][3].

Summary

I have presented multiple approaches to minimize typing when changing directories. I am honestly a bit surprised at how many ways I found. Which of these approaches do I actually use?

  • I set my CDPATH to my home directory as follows: export CDPATH=~
  • I use aliases to point to blog directories as shown above
  • I use the i3 Tiling Window Manager as my “daily driver”, and customize the screen layout when doing software development similar to the screenshot shown above.

CDPATH works well when all the directories you want to switch to are at the same level, such as subdirectories within your home directory.

Alias works well when the directories you want to switch to are at different levels, such as the directory structure imposed by the Hugo static site generator software I use for this blog. Plus, you can type theme to change to a directory named blog!

Adopting a tiling window manager like i3 requires a steep learning curve. For me it was worth the effort, but I prefer using the keyboard rather than a mouse. I will discuss i3 in a future post.

Have fun changing directories!!