How Do I Navigate Files and Directories?
Building your workspace from the command line — mkdir, cp, mv, and the art of staying organized
After this lesson, you will be able to:
- Create directories with
mkdirand nested structures withmkdir -p - Navigate the file system with
cdand understand.,..,~ - Copy files and directories with
cpandcp -r - Move and rename files with
mv - Remove files and directories with
rmandrm -r - View file contents with
cat,less,head, andtail - Use wildcards (
*,?,[...]) to match multiple files
Your Workspace Is Empty
You’ve opened your terminal, typed ls, and seen… almost nothing. Maybe a Desktop folder or a Downloads directory. But where do your labs go? Where does your source code live?
In CSCD 210, VS Code handled this for you — you cloned a repo and the file explorer showed everything in a nice tree. But now you need to build that tree yourself, from the command line. And once you’re comfortable doing it, you’ll realize it’s actually faster than clicking through menus.
Let’s build a real workspace, one command at a time.
Creating, Moving, and Organizing
Creating Directories: mkdir
Start in your home directory:
cd ~
pwd
You should see /home/student (or whatever your username is). Now let’s create your course directory:
mkdir cscd240
Verify it exists:
ls
You should see cscd240 in the listing. Now let’s create the directory structure you’ll use all quarter:
mkdir cscd240/labs
mkdir cscd240/labs/lab1
mkdir cscd240/labs/lab2
mkdir cscd240/notes
Or, more efficiently, use the -p flag to create parent directories automatically:
mkdir -p cscd240/labs/lab3/src
This creates lab3 and src inside it, even though lab3 didn’t exist yet. Without -p, that command would fail because lab3 doesn’t exist.
The Trick:
mkdir -pnever complains if a directory already exists and creates any missing parent directories. Use it whenever you’re setting up nested structures. It’s like Java’sFiles.createDirectories()— safe to call even if the path already exists.
Why does this matter?
Lab setup scripts and Makefiles use mkdir -p constantly to create output directories before compilation. If you understand -p, you’ll read those scripts without confusion. If you don’t, you’ll wonder why they don’t just use plain mkdir.
Navigating: cd
Now let’s move around:
cd cscd240
pwd
Output: /home/student/cscd240. You’re inside your course directory. Let’s go deeper:
cd labs/lab1
pwd
Output: /home/student/cscd240/labs/lab1. Notice we used a relative path — we didn’t start with /.
Now go back up:
cd ..
pwd
Output: /home/student/cscd240/labs. The .. means “parent directory” — one level up.
Go up two levels:
cd ../..
pwd
Output: /home/student. Each .. goes up one level.
Some shortcuts you’ll use constantly:
cd ~ # Go home, no matter where you are
cd # Same thing — cd with no argument goes home
cd - # Go back to the PREVIOUS directory (toggle)
Key Insight:
cd -is an underappreciated shortcut. If you’re bouncing between two directories — say your source code and your test output —cd -toggles between them instantly. It’s like Alt+Tab for directories.
/home/student/cscd240/labs/lab1. What does cd ../.. do?.. moves up one directory level. From lab1, the first .. goes to labs, the second goes to cscd240. If you picked B, you went up three levels instead of two — count the .. segments separated by /.
Creating Files: touch
The touch command creates an empty file (or updates the timestamp of an existing one):
cd ~/cscd240/labs/lab1
touch hello.c
touch Makefile
ls -l
You now have two empty files ready for content. We’ll fill them in when we start writing C code in Series 2.
Viewing Files: cat, less, head, tail
Let’s say you have a file with content. Here are four ways to look at it:
cat hello.c # Print entire file to screen (good for short files)
less hello.c # Scrollable viewer (arrow keys, /search, q to quit)
head -5 hello.c # First 5 lines
tail -3 hello.c # Last 3 lines
For now, our files are empty, but these commands become essential when you’re looking at source code, compiler output, or log files.
wc (word count) tells you file statistics:
wc hello.c # Lines, words, bytes
wc -l hello.c # Just line count
Copying Files: cp
cp hello.c hello_backup.c
ls
Now you have two files. To copy a directory, you need the -r (recursive) flag:
cd ~/cscd240/labs
cp -r lab1 lab1-backup
ls
Without -r, cp refuses to copy directories — it’s a safety feature so you don’t accidentally duplicate entire directory trees.
Moving and Renaming: mv
mv does double duty — it moves files and renames them:
cd ~/cscd240/labs/lab1
mv hello_backup.c hello_v1.c # Rename
mv hello_v1.c ../ # Move to parent directory (labs/)
ls
ls ..
Moving a file to a directory moves it there. Giving it a new name renames it. You can do both at once:
mv ../hello_v1.c ./old_hello.c # Move back and rename in one step
From Java: In CSCD 210, you renamed files by right-clicking in VS Code’s file explorer. In Unix,
mv old_name new_namedoes the same thing — and it works on directories too. There’s no separate “rename” command because moving to the same location with a new name is renaming.
Why does this matter?
Every lab submission starts with organizing files in the right directories. If you mv a file to the wrong place or cp without -r on a directory, you’ll lose work or submit incomplete labs. These commands are muscle memory by Week 3.
cp -r lab1 lab1-backup. Which statement is true?cp duplicates — the original stays put. The -r flag copies the directory and everything inside it recursively. Without -r, cp refuses to copy directories at all. If you picked A, you're thinking of mv, which moves/renames rather than copying.
Deleting: rm (Handle With Care)
rm old_hello.c # Delete a file — PERMANENT, no trash can
Common Pitfall:
rmis permanent. There is no Recycle Bin, no Undo, no “Are you sure?” (unless you add the-iflag). Before runningrm, always: (1) runpwdto confirm your location, (2) runlsto see what’s there, (3) read your command carefully before pressing Enter.
For directories:
rmdir empty_directory # Only works if directory is empty (safe)
rm -r directory_name # Delete directory and everything inside (dangerous)
Use rm -i for interactive confirmation:
rm -i some_file.c
# rm: remove regular file 'some_file.c'? y
Wildcards: Pattern Matching
Wildcards let you operate on multiple files at once. The shell expands them before the command runs:
| Pattern | Matches |
|---|---|
* |
Any number of any characters |
? |
Exactly one character |
[abc] |
One character from the set |
[0-9] |
One character from the range |
[!0-9] |
One character NOT in the range |
Examples:
ls *.c # All .c files
ls lab?.c # lab1.c, lab2.c, but NOT lab10.c
ls lab[123].c # Only lab1.c, lab2.c, lab3.c
ls *.[ch] # All .c and .h files
From Java: Java’s
File.listFiles(filter)requires writing aFilenameFilteror lambda. Unix wildcards do the same filtering with a few characters. The shell handles the expansion — the command itself never sees the wildcard characters.
lab1.c, lab2.c, lab10.c, and lab2.h. Which files does ls lab?.c match?? wildcard matches exactly one character — so lab?.c matches lab + one character + .c. That gives you lab1.c and lab2.c. It does NOT match lab10.c because 10 is two characters. It doesn't match lab2.h because the extension is .h, not .c.
Seeing the Full Picture: ls -R and tree
After building your workspace, verify the structure:
cd ~/cscd240
ls -R
The -R flag lists directories recursively — every subdirectory and its contents. If tree is installed, it gives an even prettier view:
tree
cscd240/
├── labs/
│ ├── lab1/
│ │ ├── hello.c
│ │ └── Makefile
│ ├── lab2/
│ └── lab3/
│ └── src/
└── notes/
Quick Check: What's the difference between cp and mv?
cp creates a duplicate — the original stays where it is. mv moves (or renames) — the original is gone from its old location. For directories, cp requires the -r flag; mv does not.
Quick Check: Why does mkdir cscd240/labs/lab3/src fail if lab3 doesn't exist?
By default, mkdir only creates the final directory in the path. If any parent directory is missing, it fails. The -p flag tells mkdir to create all missing parent directories along the way.
Quick Check: What does the wildcard lab[!0-9].c match?
It matches files like labA.c, labx.c, or lab_.c — any file named lab followed by exactly one character that is NOT a digit (0–9), followed by .c.
Naming Conventions
The Trick: Follow these rules for filenames and you’ll avoid most headaches:
- No spaces — use hyphens (
my-file.c) or underscores (my_file.c)- Lowercase — Unix is case-sensitive;
Hello.c,hello.c, andHELLO.Care three different files- Meaningful extensions —
.cfor C source,.hfor headers,.ofor object files- Bad:
Lab 1 Final (2).c— spaces, uppercase, parentheses- Good:
lab1-final.c
You’ve Built Your Workshop
You can now create, navigate, copy, move, and delete files and directories from the command line. That’s the foundation for everything else this quarter — every lab starts with setting up a directory structure, and every project involves managing source files.
But right now, when you get stuck, where do you go for help? You can’t hover over a command in VS Code to get a tooltip. In the next lesson, you’ll learn about Unix’s built-in documentation system — man pages — and the command history features that make the shell feel less like typing into the void.
Big Picture: The directory structure you just built by hand is exactly what
git clonecreates automatically when you clone a lab repo. Understanding the structure means you’ll know where things are when something goes wrong — and in C development, knowing where your files are is half the battle.