Navigate directories in the command line

A folder in a GUI is a directory in the command line

Photo of downtown Montreal with grey clouds in the background

What you call a folder in a GUI is a directory on the command line. They mean the same thing. A GUI gives you folders and a few other ways to organize your stuff, like documents, photos, spreadsheets, and music. On the command line, the primary way to organize stuff is with directories.

Directories are for organizing your stuff

In a GUI, there are folders dedicated to your documents, your desktop, your computer’s applications, and other stuff. In other words, a GUI provides folders for you to organize and find your stuff.

Or you don’t have to. A GUI file manager, like macOS Finder and Windows Explorer, has other ways for you to find your stuff. For example, you can just search for that last document you worked on. Forget where something is? No problem, just search for it. It’s in there somewhere, let the GUI worry about it.

Screenshot of GUI file search for “donut”

You don’t get it quite as easy with the command line. There are no guardrails, remember? So it’s important to keep your stuff in order. And the best way to do that is to use directories.

Step 0: You’ll need a command line

Is this your first time on the command line? Take a guided tour first.

You’ll need access to a computer that has a command line.

Do this: Install Tech Writer Tools.

Step 1: Working from home

We’ll start with your current directory. The current or working directory is just the command line’s idea of a default directory. When you don’t specify a directory for a command, the command assumes that you mean the current directory. Another way to look at this is that little red dot on a map, “You are here”. Your current directory is your current location in the computer’s file system. You can point to other locations (directories), too. But when you’re not pointing somewhere specific, a shell command assumes you mean your current location.

By the way, we’ll use the term sub-directory once in a while. There’s nothing special about a sub-directory, it’s just a directory like any other. The “sub-” in “sub-directory” only means that a directory happens to be in another directory.

Now, with your Terminal app showing a shell that’s eager for your next command, let’s make sure you’re starting in the right place. As a matter of good habit, you should be working in your home directory or one of its sub-directories.

Your home directory is the directory dedicated to you, where you put your projects, documents, and your other work (and fun) stuff. There are other directories on your computer for things like applications. These directories are not meant for your stuff, so we’ll stay out of them.

Do this: Enter cd.

techwriter:~$ cd
techwriter:~$ 

What happened: The cd command changes your current directory, aka working directory.

When you enter cd by itself, it sets your current directory to your home directory. This is handy when you just want to go back “home” quickly. We’ll cover how to change to a specific directory later.

Step 2: Where am I?

How do you know that cd switched you to your home directory? Look at the shell’s prompt.

techwriter:~$ 

The item after the colon (:) is your current directory, which is a tilde (~). You’re not really in a directory named ~, this is just the shell’s shorthand for your home directory.

You can also get the full path for your workding directory. Later we’ll cover what path means exactly.

Do this: Enter pwd.

techwriter:~$ pwd
/home/techwriter
techwriter:~$ 

What happened: The pwd command outputs your present working directory. In this case, your current directory is your home directory, which is /home/techwriter.

Notice that the prompt also starts with techwriter. This is your username in Tech Writer Tools. This is not a coincidence, it’s an intentional convention to name home directories after usernames. macOS, Windows, and Linux (which Tech Writer Tools is based on) all follow this convention in one way or another.

Step 3: What’s here?

Let’s see what’s in your home directory.

Do this: Enter ls.

techwriter:~$ ls
welcome.txt
techwriter:~$ 

What happened: The ls command outputs the names of files and sub-directories in a directory. By itself, ls outputs all file names and sub-directory names in the current directory.

In this case, there’s a lone file in your home directory at the moment, welcome.txt.

Step 4: Make a directory

Now let’s make a directory.

Do this: Enter mkdir donuts.

techwriter:~$ mkdir donuts
techwriter:~$ 

What happened: The mkdir command makes a directory. Unlike cd and ls, mkdir requires an argument, which is a name for the new directory.

Also, notice that mkdir doesn’t output anything (unless there’s an error). Most command line tools are pretty terse, especially the fundamental commands that do simple operations. The rationale is that it makes the commands easier to work with, since they reduce the clutter of your interactions. The command line is all about being more interactive so, ironically, commands try to stay quiet unless there’s something exceptional to report, like an error.

Let’s confirm that your new directory exists.

Do this: Enter ls.

techwriter:~$ ls
donuts welcome.txt
techwriter:~$ 

There you go, your new sub-directory donuts is ready for organizing your tasty treats.

You might also notice that donuts has a different colour than welcome.txt. And that’s all it is, you can’t add colour to a specific file or directory’s name explicitly. Names are text only. This colour is from the ls command to give you a visual indication of the item’s type. For example, directory names might be in blue while file names might be white.

Naming files and diectories

They say the 3 hardest things in computer science are:

  1. Off-by-1 errors
  2. Naming things

Just a few tips about choosing names for your files and directories on the command line:

Step 5: Specific files and directories

You’ve used the ls command by itself, which tells ls to list the names of files and sub-directories in the current directory. The ls command has ways to list specific names, too. You just have to give it an argument.

Let’s start with just a name. Give ls a name and it’ll list that file or directory.

Do this: Enter ls welcome.txt.

techwriter:~$ ls welcome.txt
welcome.txt
techwriter:~$ 

What happened: You asked ls to list names of files and sub-directories that matched its argument. In this case, only one file matched, naturally, so ls showed it.

You know what’s tasty? Dosa. Is there something in the current directory for that?

Do this: Enter ls dosa.

techwriter:~$ ls dosa
ls: cannot access 'dosa': No such file or directory
techwriter:~$ 

What happened: ls let us know that there was no matching file or directory named dosa. No surprises.

Do this: Enter ls donuts.

techwriter:~$ ls donuts
techwriter:~$ 

What happened: Nothing, apparently. But something did happen. When we give a directory name to ls, it lists the files and sub-directories in that directory. Since the donuts directory is empty, there’s nothing to list.

To make things interesting, let’s make a copy of the welcome.txt file.

Do this: Enter cp welcome.txt welcome2.txt.

techwriter:~$ cp welcome.txt welcome2.txt
techwriter:~$ 

What happened: The cp command copies files. We’ve given it 2 arguments, a source and a destination. In our case, it copied the source file, welcome.txt, to another file with the name of the destination, welcome2.txt.

Do this: Confirm the existence of welcome2.txt with the ls command.

Another thing you can do is use ls to list more than one file or directory. For example, you can list all files and directories with names that end with .txt.

If you know what these files are ahead of time, you can just enter their names explicitly.

Do this: Enter ls welcome.txt welcome2.txt.

techwriter:~$ ls welcome.txt welcome2.txt
welcome.txt welcome2.txt
techwriter:~$ 

What happened: The ls command accepts multiple arguments. You asked it to list two specific files, and it did as you asked. In fact, when it makes sense, most command lines tools accept multiple file or directory names as arguments.

Step 6: Globbing

Yeah, I know, “glob” is a weird word, probably weirder if you don’t know what it means. Let’s get into that.

What do you do if you don’t know what all the files ending with .txt are? Or what do you do if there are too many to enter without cramping your fingers? The answer to both of these questions is pattern matching in the shell, also known as “wildcards”.

Do this: Enter ls *.txt.

techwriter:~$ ls *.txt
welcome.txt welcome2.txt
techwriter:~$ 

What happened: The command output all files and directories in the current directory that end with .txt. In our case, there are two files that match, welcome.txt and welcome2.txt.

The asterisk * means “match anything that is zero or more characters”. In our case, the * happens to match the welcome in welcome.txt and welcome2 in welcome2.txt.

The “zero” in “zero or more” is something to point out. What this means is that if the rest of the pattern matches, then ls will output the name as if the * isn’t there at all.

Let’s see what this means.

Do this: Enter ls welcome*.txt.

techwriter:~$ ls welcome*.txt
welcome.txt welcome2.txt
techwriter:~$ 

What happened: The welcome*.txt pattern means “match all names that begin with welcome, possibly has some characters, then ends with .txt”. In the case of welcome.txt, the * matched zero characters while the rest of the pattern still matches.

You might already be familiar with regular expressions and recognize the use of *. Globbing is a kind of way to use regular expressions in the shell, but it works differently than conventional regular expressions, both in syntax and the way that the shell handles it.

For syntax, globbing uses the * to mean “zero or more of any character”. But in regular expressions, the * means “zero or more of the preceding item”.

In practice this means that donut* in the shell means “match items that begin with donut and possibly ends with other characters”. That would match files and directories with names like “donuts”, “donutty”, and plain “donut“.

In a regular expression, donut* means “match text that begins with donu followed by zero or more t characters. That would match text like “donut”, “donuttttttt”, and “donu” (no “t”).

Get it? Give this a think for a bit: Globbing syntax is subtly different than regular expression syntax.

As for how the shell handles globbing, here’s the other subtle but important part: when you use * in the shell for an argument, the command that acts on the globbing never sees the *. Before the shell passes your arguments to a command, the shell expands the * to insert all the matching names, then passes those names to the command.

So when you entered ls *.txt earlier, here’s what the shell did:

  1. The shell looked for all files and sub-directories in the current directory that match *.txt. In this case, those files are welcome.txt and welcome2.txt.
  2. The shell expanded that single argument, *.txt into 2 arguments, welcome.txt and welcome2.txt.
  3. The shell ran your command, ls, with expanded arguments.

Bottom line: the ls command never saw the *.txt argument. The shell only gave it the expanded arguments. And this is what’s called globbing.

Now you might be asking, “Well what’s the point of the ls command if the shell’s globbing did the heavy lifting?”

Good question. My answer has two parts:

We can see an example of this easily.

Do this: Enter echo *.txt

techwriter:~$ echo *.txt
welcome.txt welcome2.txt
techwriter:~$ 

What happened: The echo command just outputs its arguments verbatim, without processing them. It’s useful in scripts to report information, status, results, and so on. As we can see, the shell did indeed expand *.txt and passed the names of those matching files to echo, which dutifully output its arguments verbatim.

Step 7: Follow the path

We mentioned the idea of the path earlier when we saw that your home directory’s path is /home/techwriter. We use paths as a way to refer to files and directories that aren’t in the current directory.

Think of a path as a series of steps to follow to get to a specific location in the file system. We can see how this works by manually following the path of your home directory, /home/techwriter.

Our path starts with / so let’s start there.

Do this: Enter cd /.

techwriter:~$ cd /
techwriter:/$ 

What happened: The cd command put us in the directory named /, as we can see in the prompt. You can also confirm this with pwd if you want.

Do this: Enter pwd to see your current directory.

The plain ol’ / directory is the top directory in the file system. We give it a special name, root. The shell never displays root as a name explicitly, it’s just a convention for people to refer to top of the file system.

(Yeah, everyone knows the inconsistency of naming the top of something as root. It’s part historical accident and part something that computer scientists are fine with, so the name has stuck for the past few dedades.)

The path separator is the character that we use in a path to separate each “step” in a path, where each step is the name of a directory. In Linux-like systems like Tech Writer Tools and macOS, this separacter character is the forward slash, /. In Windows, it’s the backward slash, \. Be careful not to confuse the two.

Now let’s see what’s in the root directory.

Do this: Enter ls.

techwriter:/$ ls
bin  etc   lib    mnt  proc  run   srv  tmp  var
dev  home  media  opt  root  sbin  sys  usr
techwriter:/$ 

What happened: These are all the files and sub-directories in the root directory. There are a bunch. For example, the bin directory contains commands, etc contains configuration information for your computer.

Do you see the directory named root? I just told you that the shell doesn’t explicitly show the name of the root directory. I’m still right. This directory is named root because it’s actually a special directory, the home directory for the superuser. The superuser is a special user account for the system administrator. The name is root for historical reasons and we can ignore it.

Now let’s go to the home in /home/techwriter.

Do this: Enter cd home.

techwriter:/$ cd home
techwriter:/home$ 

What happened: We’re now in /home, as our prompt reminds us.

Do this: Enter ls.

techwriter:/home$ ls
techwriter
techwriter:/home$ 

What happened: There’s only one item in home, and that’s the techwriter directory, our home directory. Let’s go to it.

Do this: Enter cd techwriter.

techwriter:/home$ cd techwriter
techwriter:~$ 

What happened: We’re in our home directory, safe and sound.

Step 8: Dots that are directories

There are a couple of special directories in every directory. Like ~, they are shorthand, convenient ways of referring to specific directories.

We can see them with the ls command.

Do this: Enter ls -a.

techwriter:~$ ls -a
.  ..  .bash_profile  .bashrc  donuts  welcome.txt  welcome2.txt
techwriter:~$ 

What happened: We gave ls an option, -a. This option tells ls to list all items. (Actually, all it does is tell ls not to ignore items with names that begin with a . character.

Look closely. Notice the . and .. items. They’re directories.

Also, notice .bash_profile and .bashrc. As their colour indicates, these are files. Conventionally, Linux-like systems use so-called dot files for a user’s configuration and preferences. These particular files specify your settings for the shell.

Let’s get back to the . and .. directories.

First, there’s the directory named ., which is a single full stop character. This is the shorthand way to refer to the current directory in a path.

Then there’s the directory named .., which is 2 consecutive full stop characters. This is the shorthand way to refer to the current directory’s parent.

Let’s see what this means.

Do this: Enter ls welcome.txt.

techwriter:~$ ls welcome.txt
welcome.txt
techwriter:~$ 

What happened: As before, the ls command shows welcome.txt in the current directory.

Do this: Enter ls ./welcome.txt.

techwriter:~$ ls ./welcome.txt
techwriter:~$ 

What happened: Essentially, we’ve just entered a similar-meaning command. The path ./welcome.txt means “from the current directory, continue followling the path to welcome.txt”.

The . directory is useful to make things clearer. For example, some commands don’t use the current directory as a default, they might have their own default directory. For commands like this, you can explicitly specify the current directory with ./.

Now let’s try the .. directory.

Do this: Enter cd donuts

techwriter:~$ cd donuts
techwriter:~/donuts$ 

What happened: We’re in the donuts directory now.

Let’s do something in the parent of the donuts directory without changing our current directory.

Do this: Enter ls ../welcome.txt.

techwriter:~/donuts$ ls ../welcome.txt
welcome.txt
techwriter:~/donuts$ 

What happened: The ls command showed us welcome.txt in the parent directory of our current directory.

The path ../welcome.txt means “from the current directory, go to its parent then continue followling the path to welcome.txt”.

Take a look at the prompt before and after this command, notice that our current directory never changed even though we referred to a directory outside of it.

Do this: Enter cd ..

techwriter:~/donuts$ cd ..
techwriter:~$ 
What happened: We went up one directory, which is back at our home
directory.

It’s useful to remember that every directory has a . directory.

And every directory except the root directory has a .. directory. I’ll let you figure out why.

Step 9: It’s not all relative

There are also 3 types of path, and we’ve been using both of them:

You can easily tell the difference between an absolute and relative path by its first character. An absolute path begins with the path separator, /. A relative path begins with a sub-directory or file name.

Some examples of absolute and relative paths we’ve seen and used:

An absolute path is useful when you want to be absolutely (ahem!) specific about the location of a file or directory. The path always starts at the root directory, so there’s no ambiguity.

But that can be inflexible sometimes. Sometimes it’s useful to specify a file or directory in relation to the current directory as a starting point instead.

Do this: Use the cd and ls commands on a few relative and absolute paths.

You did it!

Congratulations, you know how to work with directories.

What you learned

Next steps