Hello again. Last time, you learned to orient yourself in the filesystem with pwd, ls, and cd, and to distinguish absolute paths from relative ones. That orientation is the first safety measure in shell work: before changing anything, know where you are.
This lesson turns navigation into controlled file management. You will create a small AI-infrastructure-style workspace, copy and rename artifacts, move files into directories, and remove only deliberately chosen test data. These are everyday operations when organizing configuration files, request samples, logs, checkpoints, and model artifacts.
The basic model: an action, a source, and a destination
Most file-management commands follow a consistent pattern:
command [options] source destination
For example:
cp notes.txt notes-backup.txt
means: copy the source file notes.txt and create a destination file named notes-backup.txt.
The core commands are:
| Goal | Command | Example |
|---|---|---|
| Create a directory | mkdir | mkdir logs |
| Create an empty file | touch | touch requests.json |
| Copy | cp | cp config.yaml config-backup.yaml |
| Move or rename | mv | mv old-name.txt new-name.txt |
| Remove a file | rm | rm temporary.txt |
| Remove an empty directory | rmdir | rmdir empty-dir |
| Remove a directory and its contents | rm -r | rm -r old-run |
The destination is important because it can mean two different things:
cp report.txt archive
- If
archiveis an existing directory, this createsarchive/report.txt. - If
archivedoes not exist, this creates a new file namedarchivecontaining a copy ofreport.txt.
When you intend a destination to be a directory, a trailing slash can make that intent clearer:
cp report.txt archive/
If archive is not actually a directory, this command fails rather than silently creating an unexpected file.
The short video below provides a visual demonstration of the commands you will use. It treats folders as directories—the two words mean the same thing in this context.
Linux/Mac Terminal Tutorial: Create, Copy, Move, Rename and Delete Files and Directories
Watch “Linux/Mac Terminal Tutorial: Create, Copy, Move, Rename and Delete Files and Directories” by Corey Schafer for a compact visual walkthrough of file operations.
Watch creating entries to see mkdir and touch. Then watch file operations for copying, renaming, moving, and the permanence of rm. Finish with directory operations, focusing on why copying and deleting directories needs recursive options.
Create a safe workspace first
Do not practice destructive commands in your home directory at random, and never practice them in locations such as /etc, /var, or /usr. Instead, create one clearly named sandbox under your home directory.
Run these commands exactly:
mkdir -p ~/ai-infra-lab/file-ops/incoming
mkdir -p ~/ai-infra-lab/file-ops/archive
cd ~/ai-infra-lab/file-ops
pwd
ls
Your final pwd should end in:
/ai-infra-lab/file-ops
The full beginning will vary because it includes your own home directory path.
Creating directories with mkdir
mkdir means “make directory”:
mkdir logs
This creates a logs directory inside your current directory.
You can create more than one directory in one command:
mkdir raw-data processed-data
For a nested path, use mkdir -p:
mkdir -p checkpoints/run-01
The -p option means “create parent directories as needed.” If checkpoints does not exist yet, Linux creates it before creating run-01. It also avoids an error if the directories already exist, which is useful in repeatable setup commands.
Create a nested directory in your sandbox:
mkdir -p checkpoints/run-01
Creating empty files with touch
A file does not need to contain data to exist. The touch command creates an empty file when the name does not already exist:
touch requests-001.json
Create a few deliberately harmless placeholder artifacts:
touch requests-001.json requests-002.json notes.txt
touch checkpoints/run-01/metadata.json
ls
These are only empty files, but their names resemble assets you might encounter in an infrastructure project:
- JSON request examples sent to an inference API;
- notes about a test run;
- metadata stored alongside a model checkpoint.
One caveat: if a file already exists, touch normally updates its modification timestamp rather than creating a new file. It is therefore useful for creating placeholders, but should not be casually run on important files when timestamps matter.
Name files for the shell, not just for humans
Linux filenames are case-sensitive: Model.bin and model.bin are different files. A practical naming convention is:
lower-case-with-hyphens
For example:
model-config.yaml
request-sample-01.json
checkpoint-run-01
Spaces are valid in names, but they require quoting or escaping at the shell:
mkdir "model outputs"
Prefer model-outputs or model_outputs instead. Simple names reduce mistakes in scripts, containers, and deployment configurations.
Copying preserves the source; moving does not
The difference between cp and mv is fundamental:
cpcreates another copy; the source remains.mvrelocates or renames the original; the old source path no longer exists.
Copy a file
Copy one request sample into the incoming directory:
cp -i requests-001.json incoming/
ls incoming
The -i means interactive. If a destination file with the same name already exists, Linux asks before overwriting it. Use -i while learning and whenever overwriting would be costly.
Now make a backup with a different filename in the current directory:
cp -i notes.txt notes-backup.txt
ls
You should now have both notes.txt and notes-backup.txt.
Without -i, the following command can silently replace notes-backup.txt if it already exists:
cp notes.txt notes-backup.txt
That is why copying is not automatically “safe” merely because the original remains intact: the destination may still be overwritten.
Copy a directory recursively
Directories can contain other directories and files. To copy the complete tree, use recursive copying:
cp -R incoming incoming-copy
ls incoming-copy
-R means recursive: copy the directory and everything beneath it. On many Linux systems, -r also works, but -R clearly conveys the intent to recurse through a directory tree.
Be attentive to whether the destination directory already exists:
cp -R incoming archive/
Because archive/ already exists, this produces:
archive/incoming/
rather than replacing archive itself.
Rename with mv
Linux has no separate general-purpose rename command for this basic task. Renaming is treated as moving a path to a new name:
mv -i notes-backup.txt notes-copy.txt
Afterward, notes-backup.txt is gone and notes-copy.txt exists.
Move and rename the file in one operation:
mv -i notes-copy.txt archive/notes-archived.txt
ls archive
The source is now gone from the current directory. Its new location is:
archive/notes-archived.txt
Move the remaining request sample without renaming it:
mv -i requests-002.json incoming/
ls incoming
Move a directory
mv works on directories without a recursive option:
mv -i incoming-copy archive/
ls archive
Since archive/ already exists, the result is a nested directory:
archive/incoming-copy/
This is a common source of surprises. Compare these two commands:
mv run-01 run-02
If run-02 does not exist, this renames run-01 to run-02.
mv run-01 experiments/
If experiments/ exists, this moves the directory to:
experiments/run-01/
Before moving a directory, inspect the destination with ls and decide whether you expect a rename or a nested move.
Wildcards are powerful because the shell expands them first
A wildcard is a pattern that the shell expands into one or more filenames before it runs your command.
The two most useful patterns are:
| Pattern | Meaning | Example |
|---|---|---|
* | Zero or more characters | request-*.json |
? | Exactly one character | request-???.json |
Suppose the current directory contains:
request-001.json
request-002.json
request-010.json
notes.txt
Then:
ls request-???.json
matches the three request files because each has exactly three characters between the hyphen and .json.
And:
ls request-*.json
matches any filename beginning with request- and ending in .json, regardless of how many characters are in the middle.
Wildcards are efficient for bulk work, but they are also risky with destructive commands. First inspect what a pattern matches using ls; only then reuse that tested pattern with cp, mv, or rm.
Learning the shell - Lesson 5: Manipulating Files
Read this concise LinuxCommand.org guide to reinforce the command patterns and, especially, the safety rule for using wildcards with deletion.
In the “Wildcards” section, read the wildcard explanation and compare * with ?. Then read the example tables in the “cp” and “mv” sections. In “mv,” read the move versus rename distinction. Finally, under “Be careful with rm!”, read the deletion warning, then finish that warning paragraph and review the “Command examples using wildcards” table.
Removing files and directories safely
Deletion is the operation where careful habits matter most. In a typical terminal workflow, rm does not send files to a graphical trash folder. Removal is intended to be permanent.
Remove an individual file
First remove notes.txt, which is still in your current directory:
rm -i notes.txt
Confirm only if the prompt names notes.txt.
Afterward, verify:
ls
The -i option is a useful guardrail. It does not make a mistaken command harmless, but it gives you a chance to stop before removal.
Remove an empty directory with rmdir
rmdir removes directories only when they are empty. Create and remove a test directory:
mkdir empty-dir
rmdir empty-dir
This is a deliberately conservative command. If a directory contains files, rmdir refuses to remove it.
Remove a non-empty directory with rm -r
To remove a directory tree, rm needs the recursive option:
mkdir -p throwaway/nested
touch throwaway/nested/temporary.txt
ls throwaway
rm -r -i throwaway
Read every prompt before responding. You should only confirm entries under the exact throwaway directory you just created.
rm -r can delete a large nested tree quickly. Avoid rm -rf while learning:
-rmeans recursively descend into directories.-fmeans force: suppress many warnings and prompts.
Together, they remove important safety checks. For normal work, prefer a narrowly specified path and add -i when deleting manually.
Test wildcards before removal
Now create disposable files:
touch scratch-01.tmp scratch-02.tmp keep.txt
ls
Preview the wildcard match:
ls scratch-*.tmp
You should see only:
scratch-01.tmp
scratch-02.tmp
Only after confirming that output, run:
rm -i scratch-*.tmp
Do not replace the pattern with *. That would match almost everything in the current directory, including directories and files you intend to keep.
A reliable removal routine is:
- Run
pwdto confirm your current directory. - Run
lsto inspect the relevant files. - Use an explicit path where possible.
- Test any wildcard with
lsfirst. - Use
rm -ifor manual deletion. - Avoid recursive deletion unless you have confirmed the directory and its contents.
For a future project, you could preserve this ~/ai-infra-lab directory as a safe location for shell experiments. Do not remove it with a broad command from your home directory.
Key takeaways
mkdircreates directories;mkdir -pcan create nested directories and required parents.touchcreates empty files when they do not already exist.cpcopies and preserves the source; usecp -ito avoid accidental overwrites.cp -Rcopies a directory tree.mvboth moves and renames. Its result depends on whether the destination already exists as a directory.rmremoves files;rmdirremoves only empty directories;rm -rremoves directory trees and requires special care.- Wildcards such as
*and?select groups of filenames. Preview them withlsbefore using them in any destructive command. - Keep experiments inside a purpose-built sandbox under your home directory.
Next, you will learn to make command output useful: redirect output to files, combine commands with pipes, and search logs using tools such as grep, sort, and tail.
Can't find a good explanation? Sign up and we'll make it for you
Sign up