Home CPSC 225

Working with Files and Directories

The Linux File System

This week we will discuss the ways in which files and directories are organized under Unix. We will also talk about commands for interacting with files and directories.

Unix uses the term "directory" while other systems use the term "folder". Here, we will call them directories, but the concept is the same.

The file system is a tree with "/" as the root of the tree. Every other directory or file is under "/" some place. Note that "/" is itself a directory (akin to the "C:" folder on Windows systems.

The following image shows a portion of the file system tree:


The Unix directory structure

Your personal files are stored in your "home directory" which is a sub-directory of /home/. When you login, you automatically start in your home directory.

The directories outside of /home/ contain programs and files used by the system. You will not need to navigate these directories normally.

Some of these are summarized below:

Most of the time, you will be working in your home directory, but it is good to have a sense of how the system as a whole fits together. When we get to administration tasks, we will talk more about some of these system directories.


Listing Files

When you are first logged in to your VM, you will be in your home directory, which is a directory under /home/ named the same as your username. The directory that you are in is called your present working directory, and you can always find what it is using the pwd command:

finlaysoni@myvm:~$ pwd
/home/finlaysoni

On this VM I am using in the examples, my username is "finlaysoni".

You can list the files and directories in your present working directory with the ls command:

finlaysoni@myvm:~$ ls
finlaysoni@myvm:~$

Right now, there is nothing in the home directory because we have not yet created any files!

You can pass ls an argument of another directory and it will tell you the contents of that directory instead of the present working directory:

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

ls also supports many options. In fact, of the 26 lowercase letters, only 'e', 'j', and 'y' are not valid options to ls. You will probably never need most of these options, but some helpful ones are listed below:

For instance, we can look at all of the hidden directories in our home directory, with details, and sizes in human readable format with:

finlaysoni@myvm:~$ ls -alh
total 44K
drwxr-xr-x 6 finlaysoni finlaysoni 4.0K Jun 20 18:09 .
drwxr-xr-x 4 root       root       4.0K Jun 19 16:26 ..
-rw------- 1 finlaysoni finlaysoni  289 Jun 20 18:09 .bash_history
-rw-r--r-- 1 finlaysoni finlaysoni  220 Apr  4 18:30 .bash_logout
-rw-r--r-- 1 finlaysoni finlaysoni 3.7K Apr  4 18:30 .bashrc
drwx------ 2 finlaysoni finlaysoni 4.0K Jun 19 16:29 .cache
drwx------ 3 finlaysoni finlaysoni 4.0K Jun 19 16:29 .gnupg
drwxrwxr-x 3 finlaysoni finlaysoni 4.0K Jun 20 18:05 .local
-rw-r--r-- 1 finlaysoni finlaysoni  807 Apr  4 18:30 .profile
drwxrwxr-x 2 finlaysoni finlaysoni 4.0K Jun 20 18:09 .ssh
-rw------- 1 finlaysoni finlaysoni 1.6K Jun 20 18:05 .viminfo

Note that the options can be given in any order. The above command could be given as ls -lah or ls -hla or any other order and it would do the same thing.

The recursive flag is worth looking at, as many other commands share a recursive option. If we list files recursively, it shows what's in the directories here, instead of just listing the directory names:

finlaysoni@myvm:~$ ls -aR
.:
.   .bash_history  .bashrc  .gnupg  .profile  .viminfo
..  .bash_logout   .cache   .local  .ssh

./.cache:
.  ..  motd.legal-displayed

./.gnupg:
.  ..  private-keys-v1.d

./.gnupg/private-keys-v1.d:
.  ..

./.local:
.  ..  share

./.local/share:
.  ..  nano

./.local/share/nano:
.  ..

./.ssh:
.  ..  authorized_keys

Now ls list the files in our home directory first. Then it goes into directories within here, and shows what's in them, as far down as needed. The deepest directory is ".local/share/nano" which stores settings for the "nano" text editor. You will also see that the .ssh directory has an authorized_keys file (if you set up the SSH keys in week 1).

Essentially, by default ls shows us what things are here directly, whereas the recursive flag shows us everything that is here, no matter how many sub-directories it is in.


Creating Directories

It is a good idea to keep the files in your home directory organized into their own directories. This keeps things tidy, makes it easier to find things and prevents you from accidentally changing the wrong files. Generally, making a directory for each project you work on is a good idea.

To create a directory, use the mkdir command which takes the name of the new directory to create as an argument:

finlaysoni@myvm:~$ mkdir new-directory

Now if we run ls again, we will see our new directory:

finlaysoni@myvm:~$ ls
new-directory

Note: it's simpler to avoid spaces in file and directory names in Unix which is why I've used a hyphen to separate the words instead of a space.

By default, mkdir does not allow you to create multiple levels of directories at one time:

finlaysoni@myvm:~$ mkdir projects/project1
mkdir: cannot create directory 'projects/project1': No such file or directory

Here, the "projects" directory did not exist, so mkdir refused to create the projects/project1 directory. If we pass mkdir the "-p" option, it will create both directories:

finlaysoni@myvm:~$ mkdir -p projects/project1

You can than move into that directory using the cd command:

finlaysoni@myvm:~$ cd new-directory 
finlaysoni@myvm:new-directory$

Now you are no longer in your home directory, but the new directory that was just created:

finlaysoni@myvm:new-directory$ pwd
/home/finlayson/new-directory

There are a couple of directory names in Unix which have special significance:


Removing directories

If we want to remove a directory, you can use the rmdir command to do so:

finlaysoni@myvm:~$ rmdir new-directory 

rmdir only allows you to remove empty directories. We will talk about removing non-empty directories later on.


Creating Files

Creating and moving into directories is fun, but to get real work done, we need files as well.

The touch command creates an empty file. This is not something you will need to do very often. Later, we will use Vim to create files and put things in them. For now, touch will let us create empty files that we can move and remove without worry. To create an empty file, run touch and pass the file name as an argument:

finlaysoni@myvm:new-directory$ touch file1
finlaysoni@myvm:new-directory$ ls
file1

Note: the other main purpose of the touch command is to update the modified time of a file. If you pass it an existing file, it doesn't change it, but updates the time as if you had.


Copying Files

The command to copy a file is cp. The first argument is the file to copy. The second argument is the location to copy it to. This can be a new filename:

finlaysoni@myvm:new-directory$ ls
file1
finlaysoni@myvm:new-directory$ cp file1 file2 
finlaysoni@myvm:new-directory$ ls
file1  file2

In this case, cp has copied 'file1' into 'file2'.

The second argument to cp can also be an existing directory name. In this case, cp will copy the first argument into the directory keeping the same name:

finlaysoni@myvm:new-directory$ ls
file1
finlaysoni@myvm:new-directory$ mkdir directory
finlaysoni@myvm:new-directory$ cp file1 directory 
finlaysoni@myvm:new-directory$ ls
directory  file1
finlaysoni@myvm:new-directory$ ls directory 
file1

Sometimes we may want to copy not just one file, but an entire directory to a new location. For instance, suppose I have "new-directory" containing a file called "file1", and I want to make a copy of the directory including the file as "backup-directory". cp by default does not do this:

finlaysoni@myvm:~$ ls new-directory 
file1
finlaysoni@myvm:~$ cp new-directory backup-directory
cp: omitting directory `new-directory'

To tell cp to copy a whole directory, we need the -R flag which stands for recursive:

finlaysoni@myvm:~$ ls new-directory                 
file1
finlaysoni@myvm:~$ cp -R new-directory backup-directory
finlaysoni@myvm:~$ ls backup-directory 
file1

Just like before, "recursive" means not just the directory, but everything inside of it as well.


Moving Files

Moving files is done with the mv command which works very similarly to cp except that it does not keep the original file where it is.

If the second argument to mv is a new name, then mv renames the first argument to that name:

finlaysoni@myvm:new-directory$ ls
file1
finlaysoni@myvm:new-directory$ mv file1 file2 
finlaysoni@myvm:new-directory$ ls
file2

If the second argument is the name of a directory, then mv will move the file into that directory:

finlaysoni@myvm:new-directory$ ls
file1
finlaysoni@myvm:new-directory$ mkdir directory
finlaysoni@myvm:new-directory$ mv file1 directory 
finlaysoni@myvm:new-directory$ ls
directory
finlaysoni@myvm:new-directory$ ls directory 
file1

You have to be somewhat careful with the mv command as it can remove files if you are not careful.

Say you have two files in a directory, named file1 and file2. Attempting to move file1 to file2 will actually erase the original file2 in the process:

finlaysoni@myvm:directory$ ls
file1  file2
finlaysoni@myvm:directory$ mv file1 file2 
finlaysoni@myvm:directory$ ls
file2

Warning: Unix commands do not warn you when they will overwrite data. Furthermore, the command prompt has no "recycle bin". If you delete something, it is likely not recoverable.

If you want to use mv in "interactive mode", it will prompt you before overwriting data:

finlaysoni@myvm:directory$ ls
file1  file2
finlaysoni@myvm:directory$ mv -i file1 file2
mv: overwrite `file2'? n
finlaysoni@myvm:directory$ ls
file1  file2

Note that mv now asked if file2 should be overwritten, to which you can answer 'y' or 'n'.


Removing Files

We have seen how to create, copy and move files. Now we will see how to remove files with the rm command.

To remove one or more files, pass them as arguments to rm:

finlaysoni@myvm:directory$ ls
file1  file2
finlaysoni@myvm:directory$ rm file1 file2 
finlaysoni@myvm:directory$ ls

rm also has a -i flag wherein it will prompt you for each file that is being removed:

finlaysoni@myvm:directory$ ls
file1  file2
finlaysoni@myvm:directory$ rm -i file1 file2 
rm: remove regular empty file `file1'? y
rm: remove regular empty file `file2'? n
finlaysoni@myvm:directory$ ls
file2

Normally, rm does not remove entire directories:

finlaysoni@myvm:new-directory$ ls
directory
finlaysoni@myvm:new-directory$ ls directory 
file1  file2
finlaysoni@myvm:new-directory$ rm directory 
rm: cannot remove `directory': Is a directory

We can tell rm to remove the directory recursively with the -R option. Again, in Unix, "recursive" means to apply some operation not just to one directory, but to every file or directory nested within that.

finlaysoni@myvm:new-directory$ ls
directory
finlaysoni@myvm:new-directory$ ls directory 
file1  file2
finlaysoni@myvm:new-directory$ rm -R directory 

You should be careful with the rm command, especially with the -R flag. Remember that Unix has no "recycle bin", so if you delete a file, it is usually not possible to get it back!

Copyright © 2018 Ian Finlayson | Licensed under a Creative Commons Attribution 4.0 International License.