Linux FilesystemLesson 2 of 8
Directories: build, reshape, remove
Create whole trees in one command, copy and move them, and remove them without losing anything you meant to keep.
mkdirrmdircpmvrmfind
After this lesson you can
- Create nested directories in one command, including from a pattern.
- Copy, rename and move whole trees.
- Remove directories safely, and know what rm -r will and will not ask.
Make directories
mkdir creates one directory. If the parent does not exist it refuses:
cd ~/lab
mkdir projects/web
mkdir: cannot create directory ‘projects/web’: No such file or directory
-p creates every missing parent, and does nothing if the directory already exists. That makes it safe to run twice, which is why scripts use it everywhere:
mkdir -v -p projects/web/css projects/api
mkdir: created directory 'projects'
mkdir: created directory 'projects/web'
mkdir: created directory 'projects/web/css'
mkdir: created directory 'projects/api'
-v (verbose) prints what it did. Without -p, an existing directory is an error:
mkdir projects/web/css
mkdir: cannot create directory ‘projects/web/css’: File exists
Build a whole layout from a pattern
The shell expands braces before the command runs, so one command can create a whole layout:
mkdir -p demo/{src,docs,tests}
ls demo
docs src tests
echo shows what the shell will pass, which is a good habit before anything destructive:
echo demo/{src,docs,tests}
demo/src demo/docs demo/tests
See a tree
tree is not installed everywhere. find always is, and ls -R is close:
ls -R projects
projects:
api web
projects/api:
projects/web:
css
projects/web/css:
find projects -type d | sort
projects
projects/api
projects/web
projects/web/css
-type d keeps directories, -type f keeps files. To see only the top level, add -maxdepth 1. To list the directories in the current location, ls -d */ also works.
Copy a directory
cp refuses a directory unless you ask for recursion:
touch projects/web/index.html projects/web/css/site.css
cp projects/web projects/web2
cp: -r not specified; omitting directory 'projects/web'
cp -r projects/web projects/web-backup
find projects/web-backup | sort
projects/web-backup
projects/web-backup/css
projects/web-backup/css/site.css
projects/web-backup/index.html
If the target already exists, cp -r source target puts source inside it as target/source. If it does not exist, the copy becomes target. Check which one you have before you run it.
Move and rename
mv does both jobs, because renaming is moving within the same directory:
mv projects/web-backup projects/archive
mv projects/archive/index.html projects/archive/home.html
find projects/archive | sort
projects/archive
projects/archive/css
projects/archive/css/site.css
projects/archive/home.html
mv silently overwrites an existing target file. -n refuses to, and -i asks first:
mv -n projects/web/index.html projects/archive/home.html
mv: not replacing 'projects/archive/home.html'
Moving inside one filesystem only rewrites a directory entry, so it is instant for a tree of any size. Across filesystems it has to copy and then delete.
Remove directories
Two commands, two levels of caution:
rmdir projects/api
rmdir only removes an empty directory and fails otherwise:
rmdir projects/archive
rmdir: failed to remove 'projects/archive': Directory not empty
rm on a directory needs -r:
rm projects/archive
rm: cannot remove 'projects/archive': Is a directory
rm -r projects/archive
There is no recycle bin. A removed tree is gone. Make it a habit to look before you remove:
ls projects/archive
rm -r projects/archive
Remove a chain of empty parents with -p:
mkdir -p a/b/c
rmdir -p a/b/c
It stops at the first directory that is not empty.
Names with spaces
The shell splits on spaces, so an unquoted name becomes several arguments:
echo x > "my file.txt"
rm my file.txt
rm: cannot remove 'my': No such file or directory
rm: cannot remove 'file.txt': No such file or directory
Quote the name, or escape each space:
rm "my file.txt"
rm my\ file.txt
The best habit is to avoid spaces in names you create, and to quote every name you did not create.
Don’t remove the directory you are standing in
Linux lets you:
mkdir -p ~/lab/x/y
cd ~/lab/x/y
rmdir ~/lab/x/y
pwd
/home/alex/lab/x/y
The shell still believes it is there, but the directory is gone, and creating files in it fails. Run cd ~ to recover.
Practice
0 of 5 done
Do these on your own system. They get harder. Check each result, then tick it off.
- Warm-up
Build a tree in one command
Make
~/lab/sitewith three subdirectories,css,jsandimg, using a singlemkdircommand. Then list every directory belowsite.Check your result
find ~/lab/site -type d | sort/home/alex/lab/site /home/alex/lab/site/css /home/alex/lab/site/img /home/alex/lab/site/jsHint
-pcreates parents. Braces expand to several names:{a,b}.Solution
mkdir -p ~/lab/site/{css,js,img} - Warm-up
Read the error, then fix it
Run
mkdir ~/lab/docs/2026/notes. It fails. Say why in one sentence, then create the directory with one command.Check your result
The first command prints
mkdir: cannot create directory '/home/alex/lab/docs/2026/notes': No such file or directory, becausedocsand2026do not exist yet. After the fix, this prints the path:ls -d ~/lab/docs/2026/notesHint
The parents are missing.
Solution
mkdir -p ~/lab/docs/2026/notes - Practice
Copy a tree and rename the copy
Copy
~/lab/siteto~/lab/site-backup, then rename the copy to~/lab/archive-2026. Prove the two trees have the same structure with a command that prints nothing when they match.Check your result
diff -r ~/lab/site ~/lab/archive-2026 && echo identicalidenticalHint
cpneeds a flag to copy directories.mvrenames when the target does not exist.Solution
cp -r ~/lab/site ~/lab/site-backup mv ~/lab/site-backup ~/lab/archive-2026 diff -r ~/lab/site ~/lab/archive-2026 && echo identical - Practice
Remove only the empty directories
Create the setup below. Then remove every empty directory under
~/lab/scratchwith one command, without touchingfullor the file inside it.mkdir -p ~/lab/scratch/{empty/deeper,full} touch ~/lab/scratch/full/keep.txtCheck your result
find ~/lab/scratch | sort/home/alex/lab/scratch /home/alex/lab/scratch/full /home/alex/lab/scratch/full/keep.txtHint
findcan select empty directories and delete what it selects. It deletes children before parents, soemptyis empty by the time it is reached.Solution
find ~/lab/scratch -type d -empty -delete - Challenge
Move a tree whose names contain spaces
Create
~/lab/Q4 Report/2026 plan/budget.txt(names contain spaces). Move the wholeQ4 Reporttree into~/lab/archive/by copying it first and removing the original only after you have checked the copy. The original must be gone at the end and the file must exist in the archive.Check your result
find ~/lab/archive -name 'budget.txt' ls ~/lab | grep -c 'Q4 Report'/home/alex/lab/archive/Q4 Report/2026 plan/budget.txt 0Hint
Quote the names, or escape each space with a backslash. Make
archivebefore you copy into it.Solution
mkdir -p "$HOME/lab/Q4 Report/2026 plan" "$HOME/lab/archive" touch "$HOME/lab/Q4 Report/2026 plan/budget.txt" cp -r "$HOME/lab/Q4 Report" "$HOME/lab/archive/" find "$HOME/lab/archive" -name budget.txt rm -r "$HOME/lab/Q4 Report"