Work with Files and Directories - Take Control of the Mac Command Line with Terminal (2015)

Take Control of the Mac Command Line with Terminal (2015)

Work with Files and Directories

Much of what you’ll need to do on the command line involves working with files in some way—creating, deleting, copying, renaming, and moving them. This chapter covers the essentials of interacting with files and directories.

Create a File

I want to mention a curious command called touch that serves two interesting functions:

· When applied to a nonexistent file, touch creates an empty file.

· When applied to an existing file or folder, touch updates its modification date to the current date and time, marking it as modified.

Try entering the following command:

touch file1

Now use ls -l to list the contents of your current directory. You’ll see file1 in the list. This file that you’ve just created is completely empty. It doesn’t have an extension, or a type, or any contents. It’s just a marker, though you could use a text editor, for example, to add to it.

Why would you do this? There are occasionally situations in which a program behaves differently based solely on the existence of a file with a certain name in a certain place. What’s in the file doesn’t matter—just that it’s there. Using touch is the quickest way to create such a file.

But for the purposes of this book, the reason to know about touch is so you can create files for your own experiments. Since you’re creating the files, you can rename, move, copy, and delete them without worrying about causing damage. So try creating a few files right now with touch.

Note: Remember, if you want to create a file with a space in the name, put it in quotation marks (touch "my file") or escape the space character (touch my\ file).

As for the other use of touch—marking a file as modified—you might do this if, for example, the program that saved it failed to update its modification date for some reason and you want to make sure your backup software notices the new version. You use exactly the same syntax, supplying the name of the existing file:

touch file1

When applied to an existing file, touch doesn’t affect its contents at all, only its modification date.

Create a Directory

To create a directory (which, of course, appears in the Finder as a folder), use the mkdir (make directory) command. To make a directory called apples, you’d enter the following:

mkdir apples

That’s it! Other than the fact that you can create a new directory in some other location than your current one (for example, you could enter mkdir ~/Documents/apples), and the fact that spaces, apostrophes, or quotation marks in directory names must be escaped (see Spaces in Paths), there’s nothing else you need to know about mkdir at this point.

Copy a File or Directory

To duplicate a file (in the same location or another location), use the cp (copy) command. It takes two arguments: the first is the file you want to copy, and the second is the destination for the copy. For example, if you’re in your home directory (~) and want to make a copy of the file file1 and put it in the Documents directory, you can do it like this:

cp file1 Documents

The location of the file you’re copying, and the location you’re copying it to, can be expressed as relative or absolute paths. For instance:

cp file1 /Users/Shared

cp /Users/jk/Documents/file1 /Users/Shared

cp file1 ..

cp ../../file1 /Users/Shared

If you want to duplicate a file and keep the duplicate in the same directory, enter the name you want the duplicate to have:

cp file1 file2

Likewise, if you want to copy the file to another location and give the copy a new name, specify the new name in addition to the destination:

cp file1 Documents/file2

Avoid Overwriting Files When Copying

Look back at the first example:

cp file1 Documents

Anything strike you as suspicious about that? We know there’s a file called file1 and a directory called Documents in the current directory, so will this command copy file1 into Documents or make a copy in the current directory and name the copy Documents (potentially overwriting the existing directory)? The answer is: cp is smart. The command assumes that if the second argument is the name of an existing directory, you want to copy the file to that directory; otherwise, it copies the file in the current directory, giving it the name of the second argument. It won’t overwrite a directory with a file.

But, in fact, cp is not quite as smart as you might like. Let’s say there’s already a file in Documents that’s called file1. When you enter cp file1 Documents, the command happily overwrites the file that’s already in Documents without any warning! The same goes for duplicating files in the same directory. If the current directory contains files file1 and file2, entering cp file1 file2 overwrites the old file2 file with a copy of file1!

Fortunately, you can turn on an optional warning that appears if you’re about to overwrite an existing file, using the -i flag. So if you enter cp -i file1 Documents and there’s already a file1 in Documents, you’ll see:

overwrite Documents/file1? (y/n [n])

Then enter y or n to allow or disallow the move. “No” is the default.

Because the -i flag can keep you out of trouble, I suggest you always use it with the cp command. Or, for an easier approach, set up an alias that does this for you automatically; see Create Aliases.

Copy Multiple Files

You can copy more than one file at a time, simply by listing all the files you want to copy, followed by the (single) destination where all the copies will go. For example, to copy files named file1, file2, and file3 into /Users/Shared, enter this:

cp file1 file2 file3 /Users/Shared

Copy a Directory

You can use the cp command to copy a directory, but you must add the -r (recursive) flag. For instance, given a directory named apples, this command would produce an error message:

cp apples ~/Documents

The correct way to enter the command is as follows:

cp -r apples ~/Documents

Slashes Away

Avoid putting a slash at the end of the source directory when using cp -r. That slash causes the command to copy every item within the directory (but not the directory itself) to the destination. For example, cp -r apples/ ~/Documentswouldn’t copy the apples directory to your ~/Documents directory, but rather copies the contents of the apples directory to your ~/Documents directory—probably not what you want.

If you use tab completion with the cp command, be extra careful, because tab completion adds trailing slashes automatically.

Move or Rename a File or Directory

If you want to move a file from one location to another, you use the mv (move) command. This command takes two arguments: the first is what you want to move, and the second is where you want to move it.

For example, if you’re in ~ and you want to move file1 from the current directory to the Documents directory, you can do it like this:

mv file1 Documents

As with cp, the location of the file you’re moving, and the location you’re moving it to, can be relative or absolute paths. Some examples:

mv file1 /Users/Shared

mv /Users/jk/Documents/file1 /Users/Shared

mv file1 ..

mv ../../file1 /Users/Shared

If you want to rename a file, you also use the mv (move) command. Weird as it may sound, mv does double duty. When you’re renaming a file, the second argument is the new name. For example, to rename the file file1 to file2, leaving it in the same location, enter this:

mv file1 file2

Tip: Want to move a file from somewhere else to your current directory, without having to figure out and type a long path? You can represent your current location with a period (.), preceded by a space. So, to move file1 from ~/Documents to your current directory, enter mv ~/Documents/file1 . on the command line.

Avoid Overwriting Files When Moving

The mv command works the same way as cp when it comes to overwriting files: it won’t overwrite a directory with a file of the same name, but it will happily overwrite files unless you tell it not to do so.

Fortunately, mv supports the same optional -i flag as cp to warn you when you’re about to overwrite a file. So if you enter mv -i file1 Documents and there’s already a file1 in Documents, you’ll see this:

overwrite Documents/file1? (y/n [n])

You can then enter y or n to allow or disallow the move. Again, “no” is the default.

As with cp, the -i flag is such a good idea that I suggest you get in the habit of using it every single time you enter mv. Alternatively, you can set up an alias that does this for you automatically; see Create Aliases.

Move and Rename in One Go

Since mv can move and rename files, you may be wondering if you can do both operations at the same time. Indeed you can. All it takes is entering the new name after the new location. For instance, if you have a file named file1 and you want to move it into the Documents directory where it will then be called file2, you can do it like this:

mv file1 Documents/file2

Move Multiple Files

You can move several files at once, simply by listing all the files you want to move, followed by the (single) destination to which they’ll all go. For example, to move files named file1, file2, and file3 into /Users/Shared, enter this:

mv file1 file2 file3 /Users/Shared

Wildcards with mv

You can use wildcards like * with mv—for example, entering mv *.jpg Pictures moves all the files from the current directory ending in .jpg into the Pictures directory. But when using mv to rename files, wildcards may not work the way you expect. For example, you cannot enter mv *.JPG *.jpeg to rename all files with a .JPG extension to instead end in .jpeg; for that, you must use a shell script (read Command-Line Recipes for an example).

Delete a File

To delete a file, use rm (remove), followed by the filename:

rm file1

Tip: To try this out safely, use touch to create a few files, enter ls to confirm that they’re there, then use rm to remove them. Then enter ls again to see that they’ve disappeared.

You can delete multiple files at once by listing them each separately:

rm file1 file2 file3 file4

And, of course, you can use wildcards:

rm file*

Needless to say, you should be extra careful when using the * wildcard with the rm command!

Warning! The rm Command Has No Safety Net

If you put something in the Mac OS X Trash, you can later drag it back out, up until the moment you choose Finder > Empty Trash. But the rm command (and the rmdir command, described next) has no such safety net. When you delete files with these commands, they’re gone—instantly and completely!

If you want to be especially cautious, you can follow rm with the -i flag, which requires you to confirm (or disallow) each item you’re deleting before it disappears forever—for example, rm -i cup* prompts you to confirm the deletion of each file that has a name beginning with cup.

Delete a Directory

Just as you can delete a folder in the Finder by dragging it to the Trash, you can delete a directory on the command line with the rmdir (remove directory) command.

To delete a directory named apples, you can enter this:

rmdir apples

As with rm, you can delete multiple directories at the same time:

rmdir pomegranates pomelos

rmdir pome*

This command works only on empty directories. (A directory can have invisible files created by Mac OS X; don’t assume it’s empty just because you didn’t put anything there.) If you run rmdir on a non-empty directory, you get this error message:

rmdir: apples: Directory not empty

This is a safety feature designed to prevent accidental deletions. If you’re sure you want to delete a directory and its contents (including subdirectories), use the rm command with the -r (recursive) flag:

rm -r apples

Use Symbolic Links

If you’ve been using a Mac for a while, you’ve probably encountered the concept of an alias in the Finder, which is a shortcut to a file or folder stored somewhere else. Aliases are handy if you want quick access to an item in more than one location, but don’t want to duplicate it. (Don’t confuse a Finder alias with the alias command you use to make shortcuts to other commands in Terminal; see Create Aliases.)

Unix, too, has something that acts almost like a Finder alias: a symbolic link (or symlink). You can create a symbolic link to a file or directory on the command line, and it will (for the most part) behave the way a Finder alias does.

There are a couple of key differences, however:

· With an alias, if you move or rename the original file or folder, the alias will still work as you’d expect. With a symlink, if you move or rename the original item, the link will no longer function. (But, if you later put an item with the original name in the original location, the link will start working again.)

· Aliases to files normally work the same way on the command line as they do in the Finder. So, if you entered open alias-name—in other words, if you used the open command on an alias you created in the Finder—the alias’s target file would open in its default application. However, the same is not true of aliases to folders. Folder aliases don’t work on the command line, so if you want to be able to use, for example, the cd command to go into a folder using a shortcut, that shortcut must be a symlink.

Making a symlink is useful when you want to create something that functions on the command line pretty much like an alias in the Finder. You may also find cases where you want to put an app’s default folder in another location, but if you replace the original with an alias, it may not work—in most cases, using a symlink instead will do the trick.

To create a symlink, you use this formula:

ln -s from to

where from and to are replaced with the paths to the original item and the symbolic link’s new location, respectively.

For example, let’s say I want to create a symbolic link to my ~/Pictures directory and put it on my Desktop. I’d do it like this:

ln -s ~/Pictures ~/Desktop

The key thing to remember is that the from argument is the path to the item you want to link to, including its filename, and the to argument is the path to where you want the symlink to be stored (with or without a filename). If you leave off the filename (as in the example above), the symlink will have the same name as the original file or directory. However, if you want the symlink to have a different name, you can specify that in the to argument, like this:

ln -s ~/Pictures ~/Desktop/photographs

If you create a symlink in Terminal and look at the resulting icon in the Finder, you’ll see a little arrow in the lower left, just like an alias.