Linux Command Line

File system paths and navigation

The file system is the part of your operating system that organizes your data on storage devices like disk drives. It also provides the means for programs to open, read from, and write to files. When you use bash (or other shells) to open a file or run a program, bash interacts with the file system to get the data you asked for.

Linux (like Windows and macOS) uses a hierarchical file system based on directories (other systems call these folders). A directory is itself a file (managed by the system) which lists its contents with details such as file size and access permissions. This list can include other directories, allowing a directory to contain subdirectories to any depth you like.

Linux treats all files as sequences of bytes, and leaves the meaning of those bytes to individual programs. Any program can read or write any file (provided you have permission to do so!).

In particular, the file system doesn't use file extensions (like .txt) to control which programs can open a file. You'll still see these in file names so humans know what the file contains, and so certain programs can understand how to process the file.

File system paths

You identify files on your computer using a path to the file, which tells the file system how to find the file. There are two different kinds of paths: absolute paths and relative paths.

Absolute paths

Absolute paths specify a file or directory location starting from the root directory. This directory is the top of the file system hierarchy and is written with a forward slash ("/"). Every file and directory in the system is contained within this root directory.

All absolute paths begin with a forward slash, meaning "start at the root." The path then contains the names of directories, separated by slashes. This describes the directories you would enter as you move to the file. The final name in the path is the file or directory the path identifies. For example:

  • /usr/bin/date means, "from the root directory enter the directory usr; then enter the directory bin; then you'll find the file date (this is the program run by the date command).
  • /home/re268 means, "from the root directory enter the directory home; then you'll find the directory re268 (my home directory).

Absolute paths do not change (unless you move the file), but can be quite long for files contained in many subdirectories. To save on typing, shells provide an alternative means to access "nearby" files.

The working directory and relative paths

As you work, your shell keeps track of your current working directory. Linux users often say they are "in" (or "working in") a directory while it is their working directory. It is very common for your shell prompt to include the name of the working directory. You can also ask the shell to print the (absolute) path of the working directory with the pwd command.

pwd - print name of current/working directory

$ pwd [OPTION]...

Relative paths specify a file or directory location starting from the working directory (rather than the root directory). This lets you refer to files in the working directory by name alone, or to files in subdirectories starting from the working directory (instead of from "/").

Example: Working on a project in your home directory

As the semester progresses, I might organize my home directory by creating a cosc051 directory, with subdirectories for each project. I might open my reference solution to the first programming project (in vim) using an absolute path.

$ vim /home/re268/cosc051/project1/main.cpp

If my home directory (/home/re268) is my current working directory, I could open the same file with a relative path:

$ pwd
/home/re268
$ vim cosc051/project1/main.cpp

The shell looks for cosc051 in my current working directory and interprets the path from there.

I might also choose to change my working directory to project1, and use an even simpler relative path:

$ cd cosc051/project1
$ pwd
/home/re268/cosc051/project1
$ vim main.cpp

Every Linux directory contains two special directory names that can be used in relative paths:

  • A single dot, ., which always means "the current directory"
  • A double dot, .., which always means "the parent of the current directory"

The single dot is useful for specifying that you mean a file in the current directory and not a shell command. A common example of this is writing ./a.out to mean "in the current directory; the file a.out."

The double dot is useful for relative paths that go "back" up the directory hierarchy (and sometimes into a different branch). I could specify the home directory /home/clay while in my home directory using the relative path ../clay, which means "go back to /home, then into the directory clay.

Home directories

Each user of a Linux computer has a home directory where they can store their personal files and programs. By default, no other user can view or change files in your home directory. Your home directory is also the default working directory when you begin a shell session. Your home directory name is the same as your username, and is a subdirectory of /home.

You interact with files in your home directory often enough that bash provides a special nickname for it. Any time you type a path beginning with a tilde ("~"), bash understands it to mean "my home directory" (this is called tilde expansion). You can use this to write relative paths starting in your home directory even when your working directory is somewhere else.

Warning: Tilde refers to the home directory of the user that types it

Bash understands the relative path ~/main.cpp based on the user who types it. It refers to a file in my home directory when I use it, and a file in your home directory when you use it.

Bash provides a related shortcut for referring to the home directory of a particular user. When you type a tilde followed by a username, bash understands it as the home directory of that user. So ~re268/main.cpp refers to a file in my home directory no matter who types it.

Windows allows multiple root directories, distinguished by letter names (C:\ typically contains Windows itself; N:\ might be a network-mapped drive).

Linux always has a single logical root, even when files are spread over multiple physical drives. Windows also uses backslashes in paths while Linux uses forward slashes.

MacOS users will find Linux paths familiar. This is because macOS is a descendent of the BSD family of Unix - it's a cousin of Linux!

The Linux directory tree has many cryptic names and an odd structure (such as the distinction betwen /bin, /usr/bin, and /usr/local/bin). This pattern is historical, and comes from the early days of Unix when disk drives were too small to hold the entire operating system and all user data.

If you are curious about the original meaning of these directories, you can read about the hierarchy with man hier (though this man page is not installed on all Linux distributions)

Navigating the file system

You can interact with any file in the system by typing its absolute path, but it's often easier to change your working directory so you can type short (relative) paths to the files you're interested in. The cd command (for "change directory") lets you select a new working directory.

cd - change the current directory

$ cd [dir]

The cd command takes a single argument, which is a path to a directory that you want to move to. The path you give can be absolute or relative to your current working directory, depdneing on where you are and where you want to go.

The cd command also has two special behaviors. If you provide a dash ("-") as the argument, you'll go to your last working directory (before the current one). If you provide no argument, then cd uses your home directory as the default and takes you home.

Unlike a graphical interface (like Explorer or Finder) where you'd move "one step at a time" by clicking into (or backing out of) each directory, you can use cd to move into any directory from any starting point. If you know where you want to go, you can get there very quickly!

The PATH environment variable

Bash lets you run any program by typing a path to the program. One example is the date command, which has the path /usr/bin/date.

Running the date command

$ /usr/bin/date
Fri Jan 22 4:50:09 EST 2021
$

In an earlier example we ran the date command by typing just its name, even though our working directory was not /usr/bin. How did bash know where to find this program?

The search path

When you type the name of a command or program, bash searches for it using an environment variable named PATH (this is often called "your path"). The PATH holds a colon-separated list of directory paths. Bash searches by looking in each directory for a program whose name matches the command you typed.

Example: Displaying your PATH with echo

You can ask bash to print the contents of the PATH variable using the echo command:

Notice that, when you print an environment variable with echo you type a dollar sign in front of its name.

You can also check whether a command is in your path using the which command.

which - shows the full path of (shell) commands

$ which [options] programname [...]

When you use which, it searches your PATH for the command you provided. Instead of running the command, it prints the full path to the program that would run if you typed the command into bash. If the command isn't in any directory in your path, which prints an error reporting this fact.

Warning: Your PATH doesn't (usually) contain .

It's good practice to use absolute paths in your PATH so the commands found there are the same no matter what your working directory may be. This means that "." typically is not in your path.

This often comes up when you want to run your newly-compiled C++ program (named a.out by default).

$ a.out
-bash: a.out: command not found

The error appears because a.out isn't in any directory in your PATH!

You can avoid this by providing a relative path starting with ./ so bash knows your program is in the current directory.

$ ./a.out

PATH is one of many environment variables whose values control how bash behaves. Other commonly used environment variables are:

  • HOME, storing the path to your home directory
  • PWD, storing the current working directory
  • OLDPWD, storing the previous working directory (for cd -)
  • SHELL, storing the path to the shell program itself

You can see a list of all current environment variables and their values with the env command.

You can also set your own environment variables as you work, or in your .bashrc file to further customize your shell. Java users often set JAVA_HOME and CLASSPATH as part of configuring their working environment.