Working with Files and Folders

Table of Contents

  1. Creating Folders: mkdir
  2. Creating Files: touch
  3. Copying: cp
  4. Moving and Renaming: mv
  5. Deleting: rm and rmdir
  6. Wildcards: Working with Many Files at Once
  7. Names with Spaces and Strange Characters
  8. Try It Yourself

Everything in this chapter happens inside your practice folder. Before you start, go there:

cd ~/cli-practice

If it doesn't exist yet, go back to the end of Moving Around and create it first.

1. Creating Folders: mkdir

You've already used mkdir (make directory) to create folders. Give it one or more names:

mkdir drafts
mkdir music videos

What if you want a folder several levels deep, like projects/website/src, and website doesn't exist yet?

mkdir projects/website/src
mkdir: projects/website: No such file or directory

(The exact wording of error messages differs a little between macOS and Linux, but the meaning is the same.)

mkdir refuses to create the missing folders in between. The -p option (parents) tells it to create every missing folder along the way:

mkdir -p projects/website/src

-p also doesn't complain if the folder already exists, which makes it safe to use in scripts.

There's one more trick worth knowing. Brace expansion lets you write several names in one go — the shell expands the braces before running the command:

mkdir -p projects/website/{src,tests,docs}

That's the same as typing three separate paths: projects/website/src, projects/website/tests, and projects/website/docs. Note there are no spaces inside the braces.

2. Creating Files: touch

touch creates an empty file:

touch notes/todo.txt
touch notes/ideas.txt notes/shopping.txt

Check that they're there, and that they really are empty (size 0):

ls -l notes
-rw-r--r--  1 dara  staff  0 Oct  1 10:02 ideas.txt
-rw-r--r--  1 dara  staff  0 Oct  1 10:02 shopping.txt
-rw-r--r--  1 dara  staff  0 Oct  1 10:02 todo.txt

If the file already exists, touch doesn't change its contents — it only updates the "last modified" time. That's where the name comes from: it "touches" the file.

Empty files aren't much fun, so here's a quick way to put a line of text into one. Don't worry about the > yet — chapter 6 explains it fully:

echo "Buy rice" > notes/shopping.txt
echo "Learn the command line" > notes/todo.txt

To open a file in a graphical editor instead, code notes/todo.txt opens it in VS Code (if you have it installed), and open / xdg-open / explorer.exe from the last chapter work on files too.

3. Copying: cp

cp (copy) takes a source and a destination:

cp notes/todo.txt notes/todo-backup.txt

That copies todo.txt to a new file called todo-backup.txt in the same folder. If the destination is a folder, the copy goes inside it and keeps its name:

cp notes/todo.txt drafts/

Now there's a drafts/todo.txt. The trailing / on drafts/ is optional, but it's a good habit: it makes it obvious that you mean a folder.

You can copy several files into a folder at once — the folder always comes last:

cp notes/ideas.txt notes/shopping.txt drafts/

Copying folders

Try copying a whole folder:

cp notes notes-copy
cp: notes is a directory (not copied).

Copying a folder means copying everything inside it, and everything inside those folders, and so on. You have to ask for that explicitly with -r (recursive):

cp -r notes notes-copy

Warning: if the destination file already exists, cp overwrites it without asking. Add -i (interactive) to make it ask first: cp -i notes/todo.txt drafts/.

4. Moving and Renaming: mv

mv (move) works just like cp, except the original is gone afterwards. Move a file into a folder:

mv notes-copy/todo.txt projects/

Interestingly, there's no separate "rename" command. Renaming is just moving a file to a new name in the same folder:

mv drafts/todo.txt drafts/old-todo.txt

And unlike cp, mv works on folders without needing -r, because the files inside don't need to be copied — the folder just gets a new name or location:

mv notes-copy archive

Warning: like cp, mv silently overwrites a file with the same name at the destination. mv -i asks first.

5. Deleting: rm and rmdir

This is the one part of the command line that deserves real respect.

rm (remove) deletes files:

rm notes/todo-backup.txt

No question, no confirmation, and — the important part — no trash. Files deleted with rm don't go to the Trash or Recycle Bin. There is no "undo" and no "restore". As you saw in Files and File Systems, the data might technically still be on the disk for a while, but for all practical purposes, it's gone.

rmdir removes a folder, but only if it's empty — which makes it a safe choice:

mkdir empty-folder
rmdir empty-folder

To delete a folder and everything inside it, use rm -r:

rm -r archive

You'll often see rm -rf in tutorials. The -f (force) means "don't ask, don't complain, even if files are write-protected or don't exist". It's useful in scripts, and it's dangerous in your hands until you're confident — one wrong path and a whole folder of work disappears in a fraction of a second.

Habits that keep you safe:

  • Run pwd before deleting, so you know where you are.
  • Run ls with the exact same path first. If ls drafts/*.txt shows the files you expect, then rm drafts/*.txt will delete those files and nothing else.
  • Use rm -i when you're unsure. It asks remove drafts/old-todo.txt? for each file; type y to confirm.
  • Use Tab to complete paths instead of typing them, so a typo can't point rm somewhere else.
  • Never run a rm -rf command copied from the internet without understanding exactly what path it deletes.

6. Wildcards: Working with Many Files at Once

Typing every file name gets tedious fast. Wildcards (also called glob patterns) let you describe a group of names:

PatternMatches
*Any number of any characters (including none)
?Exactly one character
[abc]One character: a, b, or c

Let's make some files to try them on:

touch photos/beach.jpg photos/temple.jpg photos/family.png photos/scan1.pdf photos/scan2.pdf

Now:

ls photos/*.jpg        # beach.jpg  temple.jpg
ls photos/scan?.pdf    # scan1.pdf  scan2.pdf
ls photos/*            # everything in photos
cp photos/*.jpg drafts/

Here's the key thing to understand: the shell expands the wildcard, not the command. Before ls even starts, the shell looks at the folder, finds the matching names, and replaces photos/*.jpg with photos/beach.jpg photos/temple.jpg. ls just receives two ordinary arguments. That's why wildcards work the same with every command — ls, cp, mv, rm — they never even see the *.

You can test what a pattern will match, safely, using echo:

echo photos/*.pdf
photos/scan1.pdf photos/scan2.pdf

If nothing matches, zsh stops with an error (no matches found), while Bash passes the pattern along unchanged, so the command complains it can't find a file literally called *.gif. Either way, nothing happens.

Two more things to know:

  • * doesn't match hidden files (names starting with .), so rm * won't delete .env or .git. That's a deliberate safety feature.
  • rm * deletes every visible file in the current folder. This is exactly where the "run ls first" habit pays for itself.

7. Names with Spaces and Strange Characters

As you saw in chapter 2, the shell splits arguments on spaces. So this creates two files, My and Notes.txt:

touch My Notes.txt

There are two ways to keep a name with spaces together.

Quotes around the whole name:

touch "My Notes.txt"
cp "My Notes.txt" drafts/

A backslash before each space, which tells the shell "this space is part of the name":

ls My\ Notes.txt

You don't need to remember which one to use — press Tab and the shell will add the backslashes for you.

The same goes for other characters the shell treats specially, like *, ?, &, $, !, (, ) and '. If a file name contains one, quote it. Single quotes ('...') are the strictest: the shell leaves everything inside them exactly as written.

The simplest solution of all is to avoid the problem in your own files. Developers usually name files and folders in lowercase with hyphens: my-notes.txt, project-plan.md, family-photos. No spaces, no capitals, no special characters, and nothing to quote — and it's what you'll see in almost every code project.

8. Try It Yourself

Do all of this inside ~/cli-practice.

  1. In a single command, create the folders music/khmer, music/pop, and music/classical using mkdir -p and brace expansion.
  2. Create three empty files inside music/pop: song1.mp3, song2.mp3, and cover.jpg.
  3. Copy only the .mp3 files into music/khmer. Use echo to check the pattern first.
  4. Rename music/pop/cover.jpg to music/pop/album-cover.jpg.
  5. Move the whole music/classical folder into drafts, then check with ls drafts.
  6. Create a file called "Final Report.txt" (with the space), then rename it to final-report.txt.
  7. Delete everything inside music/khmer with a wildcard — but run ls with the same pattern first. Then remove the empty folder with rmdir.

You can now organize files entirely from the keyboard. Next, let's look inside those files: reading, scrolling, and editing them in the terminal.

Buy Me a Coffee

Found this tutorial helpful? Consider buying me a coffee to support more free content!