Martini Lab A blog by Chris Williams

The Command Line for Web Developers_

Want to support this site? The Command Line for Web Developers is available to purchase on Amazon in print and Leanpub in most digital formats. Sales from the book help maintain and update this site and future editions. Reader support is available on Leanpub’s discussion page.

2. Basic Commands

The Bash shell is one of many shells available for Unix. It comes from a long line of simpler shells (or interfaces) that evolved over time to make controlling the operating system (OS) more convenient for users. Shells used to be a direct part of the OS. But when Unix separated the shell interface from other parts like memory management, the shell became its own program. Because it is a stand-alone program, developers wrote their own shells to fit their needs without affecting the OS.

You might not be aware of it, but you already use a “shell” when you use your computer. Finder is a shell of sorts. It gives you access to view and open files, and it navigates to different directories. Just like Bash, Finder added new features over time to make it more convenient for you.

Many of the commands covered in this chapter have a direct correlation to operations you perform in Finder, such as viewing files in a directory, creating new directories, copying and moving files, and executing programs. These are the same kinds of file management tasks you already perform every day, so you should be able to pick them up without any problem.

Now, there are other shells besides Bash that you can use. Zsh is a popular one among the “power users” of the command line. Bash, however, is the most popular shell out there. It comes with every Mac, and it can even run on Windows.1 Most of Bash’s commands and features are available in these other shells, so learning Bash will make you comfortable with using other shells as well.

Changing directories

Each command usually has an output that prints to the screen. Enter the following command in Figure 2-1 and hit return.

Figure 2-1. Once the response from pwd prints on the next line, a new line starts with a new prompt..

You should have gotten back something that looks like /Users/YourUsername on a new line, and then the prompt on the next line. pwd means print working directory and will print the directory that you are currently in. By default, you start in your home directory. Your home directory is what your computer has set up to keep your files separate from the rest of the computer. Here, you will find your documents, music, and other files that you own. Just as a new Finder window it has a default directory, Bash does too.

$ cd Documents

This command has two parts. The first is the command itself; the second is the argument. Commands take arguments separated by spaces. The cd command took the Documents argument and moved you into the Documents directory in your home directory. This is how you navigate in Bash.

Now, for the cool part. You are going to perform a command that you previously typed, but instead of manually typing it again, use your up cursor key to find the pwd command in your Bash history and hit return. Using the cursor key doesn’t move your cursor up the screen of your terminal as you would expect in a Word document. Instead it updates your prompt with previously entered commands.

You can use the down cursor key to go forward in history as well. Cursor keys are great for when you have to repeat yourself, or when you have to go through and find something you did in the past but aren’t sure what it was. Ok, let’s go back to the home directory.

$ cd

Now, this is different from what you did previously. Because you didn’t pass any arguments to cd, it went to the default directory. Verify your current directory with pwd.

There are multiple ways you could have gone back to the home directory from Documents.

Figure 2-2. Each command shown is a valid way to navigate to the home directory.

So how do all these mean the same thing? The first one we just covered. The second one is the absolute path from the root directory. Just as we use absolute paths in web development when we refer to the root level of So how do all these mean the same thing? The first one we just covered. The second one is the absolute path from the root directory. Just as we use absolute paths in web development when we refer to the root level of a website, we use that same convention in Unix for files and directories. The third one uses the parent directory, just like in web development. This parent directory argument works in any directory you are in.

Figure 2-3. We can print the value of variables using echo and starting the variable name with ‘$’.

In the fourth example, ~ is a shortcut to mean your home directory. The tilde is the value of HOME, an environment variable that stays with you during your Bash session. ~ can be used in place of having to type out the entire value when referring to anything in your home directory. So the path of your Documents directory can be either /Users/YourUsername/Documents or simply ~/Documents.

Environment variables are global values that have a default value every time you begin a new Bash session. If you think of them in terms of variables in JavaScript, they are the predefined global values that all functions can access. Environment variables are easy to spot: they use the uppercase name convention.

You can print out the value of HOME with echo.

Here we used the echo command to return whatever value comes after it. Note that we used the $ character, so echo knows we are referring to a variable and not a string. Without $, echo would just return the string “HOME”.

Try out this exercise.

Figure 2-4. Here is how you would coplete this exercise.

Using shortcuts to execute commands

Using up and down cursor keys to navigate historic commands is one of many shortcuts available in Bash. Another one is Bash’s ability to auto-complete file and directory names for you. In the previous exercise, try just using the up and down cursor keys. Instead, for cd ~/Documents, just type cd ~/Doc and use the tab key to fill in the rest.

For auto-complete to happen, the directory has to be the only one that starts with “Doc.” In my case, when I type cd ~/D and then tab, nothing happens. If I hit the tab key again, Bash will print all my options. It turns out I have Desktop, Documents, Downloads, and Dropbox in my home directory, so I have to be a bit more specific.

By the way, if you are in a directory with only one sub-directory, then auto-complete just got a whole lot easier for you. You only need cd and tab for Bash to fill in the rest. As we go through these exercises, there will be commands that are repeated from prior exercises so that you can take advantage of the cursor keys. Also, see if the tab key is usable for auto-completing file names and directories. Not all commands we use in this book use the tab key for auto-completion, but many do.

Figure 2-5. An example of files and directories found in this directory.

Using flags on commands

A flag is an options parameter that changes the behavior of the command. Every command has a default function, and flags tell that command to change what it does to be more useful for the user.

In the example Figure 2-5,this doesn’t tell me much other than a list of names. I happen to know that these are directories, but these might be files as well given how little information is shown. ls has several options for how to use it. Instead of giving this command an argument value, we’re going to use an operation flag.

Figure 2-6 looks a lot different. Instead of a loose string of words, we have a lot more information available about these directories displayed in columns.

Figure 2-6. Dotfiles are hidden unless explicitly called.

ls has other useful flags. We see how -l prints a long format, which includes a bunch of other properties related to the items in the list. -a prints all files including hidden ones not seen by default. -F will print a / character after items to show that these are folders. All three of these flags can be used in combination as well. These flags are case sensitive too, so a lower case “f” would not work.

What are hidden files and directories?

The whole reason to use the -a flag is to show hidden files in a directory. The directory .Trash isn’t something you would see in your home folder by default because it is a “dotfile,” a file or directory whose name starts with the . character. These files usually have preference data or metadata for other functions and applications. They are hidden by default to keep directories less cluttered.

For example, .ssh is a directory that holds my security keys for programs to connect with authorized servers like .dropbox keeps information about my files on my local machine; that kind of information doesn’t need to be in the Dropbox folder itself. And .Trash is where actual files go when Finder moves items to the trash bin. There are no good reasons to make these visible to users by default, but you can easily see them and access them if you need to.

There are two particular items in this list of “hidden files” that are very important in understanding how Unix directory structures work. ./ and ../ (dot slash and dot dot slash) are present in every directory. They are a kind of pointer that we use to reference the current directory and the parent directory.

For example, if we recall the exercises of changing directories, we used cd ../ to go to the parent directory. For that to work, there has to be a ../ in the directory you are in. Otherwise, you would have to use an absolute path every time. Luckily, that isn’t the case.

Figure 2-7. dot slash and dot dot slash act like directories even though they are quite different. If you are familiar with the game Portal you, the Player, can go through both doors and portals into other rooms. The outcome is the same even though portals are not really doors. Pretend for a moment that the game lets you have multiple portals running. The dot slash portal would point back in the same room, whereas the dot dot slash would take you to the previous room.

Files have permissions

When we used ls -l in Figure 2-8, it printed a bunch of other data. So what is all this extra stuff? Well, some of it pertains to low-level information about files that almost never affect us. But other parts are straightforward. The first character, d, in drwx------+ tells us that this is a directory. The other characters pertain to the permissions of who can read or write in that directory that we’ll get into in a moment.

Figure 2-8. The long format of ls shows more information about the items in the directory.

In the second column is the count of hard links associated with that file or the files in that directory. Hard links is a Unix concept that a file can exist in multiple locations by linking to it. It’s a great way to save space if you are on a 1970s server I suppose, but this number has little to no value for us anymore. After the next two columns, you have file size, modification date, and the name. Those are helpful, but not as important as understanding how the first column correlates to columns three and four.

The third column is the file’s or directory’s owner; the fourth column is the group owner. These two columns relate to the first column as to who has access to the file or directory. Permissions have three types of owners: user, group, and world. These three owners have three types of ownership: read, write and execute. If we look at the Desktop directory, in the first column it reads drwx------+. These characters represent the permissions associated with that file or directory. The first character denotes it’s a directory, the next three are the read/write/execute values for the user, and then the next three for the group, the next three for the world.

Figure 2-9. These letters state the permission values for ~/Public.

As seen in Figure 2-9, my Public directory has these permission values: drwxr-xr-x+

These three groupings of user, group, and world permissions can be thought of as such: things I can do, things my friends can do, and things the rest of the world can do.

Owner (chriswilliams)rwx
Group (staff)rx

Executing a directory sound a bit weird because we do not normally think of opening a folder as being the same as launching an application. But when you use cd as in a previous exercise, this is executing a command in a directory.

These permissions affect how you, other programs, and other users access information on your machine. One way to understand why these permissions are important is to look at how two machines may share files on a network. Looking back at the Public directory, you can see that it has the ability for any user to view the contents of that directory because users have read access, but only the owner has write access. If this machine were sharing files across a network, a public directory would be a very convenient way for you to share a file with others with a read-only directory.

ACL: Access Control List

For our purposes, we will not be working with Access Control Lists (ACLs), but it’s good to know about them. The last character in that string of permission values is optional. It denotes an ACL. Without it, these permissions have no exceptions. But in this case, there is a special rule that doesn’t fit this scenario.

Figure 2-10. This time, we stent ls (list) two flags and an argument. We want a print of the ACL values for Public. You can think of the -e flag for showing extra information.

A file or directory can have more than one ACL. In this case, there is only one additional rule to these permissions: nobody can delete this directory, not even the user.

ACLs extend file sharing beyond traditional UNIX file permissions. This kind of flexibility gives granular permission to multiple groups or users.

You may have noticed that the Dropbox folder has an @ character instead of a + character. That is Apple’s unique way of showing that there is Apple-specific metadata. If you label your files in Finder with tags and colors, this is an example of that kind of metadata.

Moving, copying, and removing files

Now that we’ve gone through permissions and file attributes let’s start experimenting with the different ways to move files around in Bash. For these exercises, make a new directory and create a new file.

Notice the new directory sandbox and new file bucket.txt are both in the home directory. mkdir, short for make directory, created the new directory sandbox. This only works if sandbox doesn’t already exist. Try creating a directory that already exists and you will get an error. mkdir works with relative and absolute paths, so you could also use mkdir ~/sandbox.

touch is a little different. The main function of this command is to update a file’s timestamp to the immediate time. But because bucket.txt doesn’t exist, touch created an empty file with the immediate timestamp. This functions is a handy shortcut for making new files without needing a text editor.

Remember that you can still use the tab key to auto-complete these names instead of typing them out.

Figure 2-11. In this exercise, you should have a new directory and a new file.
Figure 2-12. The bucket.txt file now exists in the sandbox directory.

Move to rename

What if you create a file that wasn’t the name you wanted? When mv moves a file to another spot, it takes two arguments the file to move and the new location. You can also use mv to change the name using the same two arguments but with the new file name as part of the second argument.

Figure 2-13. Moving a file from one name to another renames that file.

You are still giving mv two valid path arguments in this case. As long as the paths are valid, the file exists, and you have write permission, you can rename the file. For example, the command in Figure 2-14 is still valid albeit not very efficient.

Figure 2-14. The move command takes two arguments: the first is the file you want to move, and the second is where to move it.

Copying files with cp

Copying a file uses the same command structure as moving.

Something very important happened here. If you have been going along with the exercises, you might have noticed that a shovel.txt file already exists in the sandbox directory. The cp command copied a file over to sandbox that already had a file with that name. We just overwrote that file with a new file. If you used cp shovel.txt sandbox again, you will have overwritten the file you just copied over. Both mv and cp will overwrite files with the same name.

Normally, when you move or copy files in Finder or Windows, you get some warning indicating you are about to overwrite something. This is not so with the command line. So you’d better be sure that is what you want to do because there is no undo or trash bin to recover anything deleted.

Figure 2-15. Copying a file to another location doesn’t require renaming.

In the example for Figure 2-16, the flag -i means interactive. You can also write it out as --interactive. This flag which is present in both cp and mv checks for existing file. If a file already exists you will get a confirmation request to input ‘y’ or ‘n’ (or just hit return for ‘n’).

Figure 2-16. Adding a flag to this command is a good way to erroneously delete an existing file.

cp is also like mv in that you can rename a file that you copy.

$ cd
$ touch shovel.txt
$ cp shovel.txt sandbox/bucket.txt

Again, we have two arguments with valid paths, and cp is going to honor this. The one catch to these is that we are copying a file, not a directory.

$ cp sandbox toolbox
cp: sandbox is a directory (not copied).

Both cp and mv will not copy directories without a flag. The recursive flag -r will go through all directories and child directories to finish the copying process. This flag is especially important for removing files and directories.

Removing files with rm

We’ve gone over moving files and copying files. What do you think the command for removing a file is?

rm, the command for removing files, has similar methods to cp and mv it takes an -i flag and there is no undo. It also uses the -r flag for directories.

rm is kind of famous, or infamous rather. If you google “Unix horror story,” there are plenty of horror stories about users inadvertently deleting files, including one from a very well-known animation company2 that nearly prevented one of its biggest movies from hitting theaters.3

Figure 2-17. rm will not delete a directory that may point to other files. -r removes those files first.

rm is kind of a big deal. First, it has some checks and balances. You have to have permission as a user to delete a file. Also, you cannot (without effort) delete the root directory. Unlike deleting something in Finder or Windows, there is no “trash” directory with rm; there is no “undo” either. So use with caution!

You’ve just replaced Finder

In this chapter, you’ve learned how to navigate around the directories in Bash and how to copy, move, create, and delete files and directories. You also learned that there is more than one way to get things done with flags, aliases, and shortcuts. Now, will you never have to use Finder again? No. But when working in the command line, it helps to keep your focus on one application instead of two for the same tasks.

In the next chapter, we will get into how to search for files and view them. As we go further into what we can do with flags and other Bash syntax, we will be able to run commands that Finder can’t do making Bash a powerful tool for handling files and directories.

  1. Windows 10 brings Bash native support. Some features aren’t fully flushed out, but you can also use third-party apps like Cygwin.
Buy on Amazon
Buy on LeanPub