Files, Directories, and Executables

The Core of the Command Line

In a desktop environment, like that of OS X, you have windows, menu bars, and the desktop to give context to what you are doing. In the command line, however, the context is solely the file system. In fact, files and directories are what make up the command line. Almost everything you do at the prompt will deal with files. Every time you type a command, you are telling the computer to execute a file.

Not only does the file system provide context for you when you're trying to work on or get information about files and directories, it also provides context for the commands you run. For example, you can use the ls command to list the files in a directory. When you run the command by itself, it uses your current directory as context, and lists the files that are in the directory you are in.

Linux/Unix File System

Let's look for a moment at some of the symbols that will help us navigate the command line:

  • / - The root directory or a separator when listing directories
  • . - The current directory (also ./) or the same level
  • .. - The directory one level up (also ../)
  • ../.. - The directory that is two levels up; that is, the directory that is one level up from ..
  • ~ - Your "home" directory, or the directory you are placed in when you log in.
  • * - The "splat" or "glob" operator. This is the wildcard of the command line and represents "any characters."

The above symbols can be combined with directory and file names to represent their locations. The path /home/ubuntu can be dissected as follows:

root directory + "home" directory + directory separator + "ubuntu" (user)
directory

While it may not make sense to do so, somewhat "nonsensical" combinations can represent valid paths. The following path is the same as /home/ubuntu:

/home/ubuntu/../.././home/ubuntu/

Let's break the above path into its parts:

  • /home/ubuntu/ - The ubuntu directory within the home directory within the root (/) directory.
  • ../../ - Up two directories (which takes us back to the root directory).
  • ./ - The same directory (which is still /).
  • home/ubuntu/ - Back down into the home directory, then the ubuntu directory.

Note that there's a dramatic difference between a path that starts with a leading slash vs one that doesn't. For example:

  • /home/ubuntu This path specifies a folder called ubuntu that lives in a directory called home, which is itself in the root directory.

  • home/ubuntu This path specifies a completely different folder. This path means there's a folder called ubuntu that lives in a directory called home, which is itself in the current directory.

The leading slash makes all the difference. Make sure to pay careful attention to that whenever you're looking at paths.

Navigating

Navigating your computer's file system is pretty easy with the help of the File System Legend above, and a few simple commands:

  • cd - change directory
  • ls - list files
  • pwd - display the current working directory

Let's get a feel for navigating the command line interface by opening up Terminal or logging in to your managed server or virtual machine and treading water for a bit. After logging in, type the following commands and note what happens after each step:

# Change directory (with no arguments)
$ cd
$ pwd
/home/ubuntu

# Change to root directory
$ cd /
$ pwd
/

# Change directory (with no arguments again)
$ cd
$ pwd
/home/ubuntu

# Go up one directory
$ cd ../
$ pwd
/home

# Show files and directories (with no arguments, it uses current directory)
$ ls
ubuntu

# Navigate into "ubuntu" directory
$ cd ubuntu
$ pwd
/home/ubuntu

# Change to ~ (home) directory
$ cd ~
$ pwd
/home/ubuntu

# Show files and directories in root directory
$ ls /
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  rootfs  run  sbin  selinux  srv  sys  tmp  usr  var

# Show files that match a certain pattern
# using the splat operator (asterisk)

# The following example may not produce the same
# results on your system. On some systems, such as
# Ubuntu, you may need to use `sudo ls /*ot` instead
# of ls /*ot, but on others, such as a Mac, you
# will only get error messages. What's important
# here is to learn how to use the commands, not
# replicate the results.

$ ls /*ot
boot root

Did you notice that typing cd by itself takes you to your "home" directory? Which command(s) made you "descend" into a directory? Which command(s) made you go up a directory? What was the difference in the output of ls vs. ls /? What do you think the output of ls ./ would be if you first ran cd /?

The last example shows that the splat (*) allows you to list files that match a pattern. The asterisk is the wildcard and represents any number of any characters, so *ot represents any file or directory that ends in ot.

Managing Files and Folders

With an understanding that "where you are" in the command line provides context for your commands, and a working knowledge of navigating the command line interface, we can move on to learning to manage files and directories from the command line.

When you open up Finder in Mac or Windows Explorer in Windows, you can see manila-folder-style directories along with icons that represent documents, images, and programs. Think for a moment about some of the things that you do with the files from time to time. Do you ever move files around? Maybe sometimes you copy a file so that you can make a new version. Have you made new directories before? It's probably not too surprising by now that you can do the same things from the command line. Some of the most frequently used commands for managing files and directories on the command line are cp, mv, mkdir, touch, and rm. Their meanings are listed here:

Command What it does
cp Copy one or more files to a new location
mv Move or rename a file or directory
mkdir Make a new directory
touch Create a new file or update modification time if a file with that name exists
rm Remove one or more files or directories

To get acquainted with these commands, go ahead and try them out. Try the following exercises to solidify your understanding of the above commands:

  1. Create a directory in your home directory called "cli-tmp".

    mkdir ~/cli-tmp
    
  2. From the home directory, create a file in the cli-tmp directory called "from-home.txt".

    cd
    touch cli-tmp/from-home.txt
    
  3. Navigate to the cli-tmp directory, then create a file called "in-cli-tmp".

    cd cli-tmp
    touch in-cli-tmp
    
  4. Try to make a directory called "in-cli-tmp" within the cli-tmp directory. What happens?

    $ mkdir in-cli-tmp
    mkdir: in-cli-tmp: File exists
    
  5. Remove the from-home.txt file.

    rm from-home.txt
    
  6. Remove the cli-tmp directory (hint use man to see how to remove a directory recursively).

    cd
    rm -r cli-tmp
    
  7. Create a nested set of directories in your home directory: cli-tmp > parents > children > grandchildren (hint: use the -p flag to do it all at once).

    mkdir -p ~/cli-tmp/parents/children/grandchildren
    
  8. Navigate to the children directory.

    cd ~/cli-tmp/parents/children
    
  9. Create a file named "bob".

    touch bob
    
  10. Move the file named "bob" to the grandchildren directory.

    mv bob grandchildren
    
  11. Copy the grandchildren directory to the parents directory with a new name: nephews.

    cp -r grandchildren ../nephews
    
  12. Copy the contents of the "nephews" directory to the "children" directory.

    cp ../nephews/* ./
    
  13. View what you've done with the tree command: tree ~/cli-tmp. Note that you may need to install the tree command:

    • On a Mac, use homebrew or a similar tool to install the tree command.
    • On AWS Cloud9, you can install tree with the sudo yum install tree command.
    • tree is pre-installed on GitHub Codespaces
    • If none of the above apply to you, try sudo apt-get install tree.
    $ tree ~/cli-tmp
    /Users/[username]/cli-tmp/
    └── parents
      ├── children
      │   ├── bob
      │   └── grandchildren
      │       └── bob
      └── nephews
          └── bob
    
  14. Remove the "bob" file from the grandchildren directory.

    rm ~/cli-tmp/parents/children/grandchildren/bob
    
  15. Remove the cli-tmp directory.

    cd
    rm -r cli-tmp
    

Executables

In the last chapter, we talked about the anatomy of commands, which was basically "command plus arguments." But what is a command really? As mentioned at the beginning of this chapter, a command is just a file. That's right: ls, mkdir, and cd are all files. Files that can be used as commands are called executables. Not all files are executables.

What makes an executable different from other files?

  1. They have special characters at the beginning to tell the computer how to execute them.
  2. They have scripts or machine language as their content.
  3. They have the executable permission (we'll talk more about this later).

To run an executable, you just type its path as the first part of your input, then type in your arguments, and hit enter, like this:

$ /bin/echo "Hello World"
Hello World

In the above example, /bin/echo is the path to the executable, and "Hello World" is the first (and only) argument.

If you want to execute a file in your current directory, you have to type ./ or the path to your current directory before the filename. For common or installed commands, you won't usually have to specify the path of the executable because the command line interface already knows where to find it. That's why you can type echo instead of /bin/echo.

When you use the echo executable, it will probably take no more than a few milliseconds to run, and the chances that it will freeze or get stuck are almost zero. Some executables, however, cause long-running processes, and it is useful at times to be able to exit out of them before they exit on their own. Some commands and executables run in a loop, and won't exit until you tell them to. Others freeze or take a lot longer than you expected, and need to be stopped short. On Unix-like systems, there is an almost ubiquitous way of exiting out of any executable's process: Ctrl + c. This key combination terminates the process by sending it a SIGINT signal.

If you are using Bash commands and accidentally create an infinite loop, you can exit out of it with Ctrl + c:

$  while true; do echo 'Hit CTRL+C'; sleep 1; done
Hit CTRL+C
Hit CTRL+C
Hit CTRL+C

The above will echo "Hit CTRL+C", then sleep for a second, until you hit Ctrl + c on your keyboard.

Note the format "Ctrl + c" means "hold down the control key, then press c, and release." You'll see other combinations like this as you learn more about programming and about using Bash.

In the next chapter, we'll discuss how the command line knows where installed commands are located.

Exercises

  1. List the hidden files in a directory.

    Solution

    You can list all files, including hidden ones, in a directory using the -a flag.

    $ ls -a
    .   .bash_history  .bash_profile  .cache   .gem    .npm
    ..  .bash_logout   .bashrc        .config  .local  .profile
    

    To only list hidden (also called dotfiles) files, you can use the following command:

    $ ls -d .*
    .   .bash_history  .bash_profile  .cache   .gem    .npm  .viminfo
    ..  .bash_logout   .bashrc        .config  .local  .profile  .ssh
    

    Video Walkthrough

    Please register to play this video

  2. List the files in the parent directory. Then list the files in the parent directory's parent directory.

    Solution

    You can list a parent directory's files using the following command:

    $ ls ..
    ubuntu
    

    What happens if you run that command from the root directory?

    $ cd /
    $ ls ..
    bin   home            lib64       opt   sbin  usr
    boot  initrd.img      lost+found  proc  srv   var
    dev   initrd.img.old  media       root  sys   vmlinuz
    etc   lib             mnt         run   tmp   vmlinuz.old
    

    As you can see, since the root directory doesn't have a parent directory, it just prints out the files in the root directory itself.

    To list the files of the parent's parent directory, just add a slash and an extra ..:

    $ cd
    $ ls ../..
    bin   home            lib64       opt   sbin  usr
    boot  initrd.img      lost+found  proc  srv   var
    dev   initrd.img.old  media       root  sys   vmlinuz
    etc   lib             mnt         run   tmp   vmlinuz.old
    

    Video Walkthrough

    Please register to play this video

  3. What's the difference between abc/ and /abc?

    Solution

    The path abc/ (also ./abc and ./abc/) are paths relative to your current working directory. The path /abc, however, is the file or directory abc in the root directory.

    Video Walkthrough

    Please register to play this video

  4. What does ../abc mean?

    Solution

    The path ../abc is a reference to the parent directory (..), and the file or directory called "abc" within that directory.

    Video Walkthrough

    Please register to play this video

  5. Suppose you are in a directory with 7 files. You need to move 6 of them into a "tmp" directory, that you have yet to create. How do you do that?

    Solution

    Let's break this up into a few steps:

    First, create the temporary directory:

    $ mkdir ~/tmp
    

    The fastest way to move all but one file is to move all the files, then move the one file back. Assuming the one file that you don't want to move is 1.file, the following commands will do the trick:

    $ mv * ~/tmp
    $ mv ~/tmp/1.file ./
    

    Video Walkthrough

    Please register to play this video

  6. Suppose you have two directories called xyz/ and abc/. How do you move all the files in abc/ that end with ".txt" into xyz/?

    Solution

    Using the glob operator *, (also known as the wildcard or just asterisk) you can move all files that match a particular pattern. First, check your pattern:

    $ ls abc/*.txt
    1.txt  2.txt  3.txt
    

    Then move the files:

    $ mv abc/*.txt xyz/
    

    Video Walkthrough

    Please register to play this video

  7. This exercise isn't a true exercise. It's a review of some common navigation tasks with no questions, solutions, or videos.

    • To get your current location, use pwd:

      $ pwd
      /home/ubuntu
      
    • To change your current directory, use cd. Using it without any arguments will take you to your home directory:

      $ cd
      $ pwd
      /home/ubuntu
      
    • You can also pass the $HOME variable as an argument, or use the ~ (tilde) as the first argument to achieve the same results:

      $ cd $HOME
      $ pwd
      /home/ubuntu
      $ cd ~
      $ pwd
      /home/ubuntu
      
    • Go to the root directory (/):

      $ cd /
      $ pwd
      /
      
    • Use the ls command to determine what files and directories are located in the current directory:

      $ cd /
      $ pwd
      /
      $ ls
      bin   dev  home  lib64  lost+found  mnt  proc  run   selinux  sys  usr
      boot  etc  lib   local  media       opt  root  sbin  srv      tmp  var
      
    • Pass a directory or a path as an argument to the cd command to go directly to that location:

      $ cd usr
      $ pwd
      /usr
      
    • You can also get a sneak peek into what directories are located in a specific path:

      $ cd /
      $ pwd
      /
      $ ls usr
      bin  etc  games  include  lib  lib64  libexec  local  sbin  share  src  tmp
      
    • Use the -lah set of flags as arguments to the ls command to get more detailed information about files and directories:

      $ cd /
      $ ls -lah
      total 112K
      dr-xr-xr-x 24 root root 4.0K Mar 16 20:56 .
      dr-xr-xr-x 24 root root 4.0K Mar 16 20:56 ..
      -rw-r--r--  1 root root    0 Mar 16 20:56 .autofsck
      dr-xr-xr-x  2 root root 4.0K Oct  1  2014 bin
      dr-xr-xr-x  3 root root 4.0K Oct  1  2014 boot
      drwxr-xr-x 16 root root 2.8K Jun  3 21:48 dev
      drwxr-xr-x 76 root root 4.0K Jun  3 21:48 etc
      drwxr-xr-x  3 root root 4.0K Sep 29  2014 home
      dr-xr-xr-x  7 root root 4.0K Mar 25  2014 lib
      dr-xr-xr-x 10 root root  12K Oct  1  2014 lib64
      drwxr-xr-x  2 root root 4.0K Mar 25  2014 local
      drwx------  2 root root  16K Mar 25  2014 lost+found
      drwxr-xr-x  2 root root 4.0K Jan  6  2012 media
      drwxr-xr-x  2 root root 4.0K Jan  6  2012 mnt
      drwxr-xr-x  3 root root 4.0K Mar 25  2014 opt
      dr-xr-xr-x 75 root root    0 Mar 16 20:56 proc
      dr-xr-x---  3 root root 4.0K Jun  3 21:48 root
      drwxr-xr-x  4 root root 4.0K Sep 29  2014 run
      dr-xr-xr-x  2 root root  12K Oct  1  2014 sbin
      drwxr-xr-x  2 root root 4.0K Jan  6  2012 selinux
      drwxr-xr-x  2 root root 4.0K Jan  6  2012 srv
      dr-xr-xr-x 13 root root    0 Mar 16 20:56 sys
      drwxrwxrwt  3 root root 4.0K Jun 10 03:34 tmp
      drwxr-xr-x 13 root root 4.0K Mar 25  2014 usr
      drwxr-xr-x 19 root root 4.0K Mar 25  2014 var
      
  8. This exercise isn't a true exercise. It's a walkthrough of some common commands with no questions or solutions. We'll find the location of so-called "default executables" by using the which command, then execute a file using its absolute path.

    • To figure out a default executable's location, you can use the which command:

      $ which touch
      /bin/touch
      
    • Now we can execute the touch command using its full path or name:

      $ cd
      $ touch test
      $ ls
      test
      $ /bin/touch test2
      $ ls
      test test2
      
    • We can do the same thing now with the rm command:

      Warning!

      The "rm" command is extremely dangerous. There is no easy, or even moderately difficult, way to restore what you delete with the "rm" command!

      $ cd
      $ rm test
      $ ls
      test2
      $ which rm
      /bin/rm
      $ /bin/rm test2
      $ ls
      

    Video Walkthrough

    Please register to play this video