Command-Line Navigation, File Search, and Shell Basics
Introduction
Command-line navigation and file search support everyday Git and front-end work. This first version-control lesson aligns with Meta’s "Version Control" course. Git can be used through a terminal, editor, or graphical client; here you practise the command line workflow. Professional front-end work depends on it. You install packages with npm, start a development server with npm run dev, run Jest tests, and drive Git, and all of these happen in a terminal. The terminal is not a relic. It is scriptable and widely used, but shells, command versions, and operating systems differ. Learn the common model and check the options available on your machine.
By the end of this lesson you will be able to move around a project, create and inspect files and folders, read and search text, chain commands together, and understand how the shell finds programs and handles permissions. The practice scenario is original: you are joining the Harbor Workshops team and must set up the project folder, find where a bug is mentioned, and prepare the repository for the Git lessons that follow.
Learning objectives
- Explain the roles of the terminal, the shell, and the file system, and read a path correctly.
- Navigate with
pwd,ls, andcd, using absolute paths, relative paths,.,.., and~. - Create, copy, move, and delete files and folders with
mkdir,touch,cp,mv, andrm, and know which operations cannot be undone. - Read and search files with
cat,less,head,tail, andgrep. - Combine commands with pipes and redirection.
- Describe environment variables,
PATH, and file permissions at the level needed to diagnose common errors. - Use tab completion, history, and
--helpormanto work faster and learn commands on your own. - Prepare a project folder with a
.gitignore,README.md, andpackage.jsonready for version control.
1. Terminal, shell, and file system
Three terms are often mixed up.
- The terminal (or terminal emulator) is the window that displays text and takes keyboard input.
- The shell is the program running inside the terminal that reads your commands and runs them. Common shells are bash, zsh (the default on current macOS), and PowerShell on Windows. Windows users can also use Git Bash or the Windows Subsystem for Linux (WSL), which give a bash-style shell. This lesson uses Bash-style commands, most of which also work in zsh. PowerShell has different syntax and option conventions; do not paste these examples into it unchanged. GNU-specific options are identified where relevant.
- The file system is the tree of folders and files on disk.
A command has a name, optional flags (also called options), and arguments:
ls -l src
# ls -> command
# -l -> flag (long listing)
# src -> argument (what to list)Short flags use one dash (-l) and can often be combined (-la). Long flags use two dashes (--all). The prompt (often ending in $ or %) tells you the shell is waiting for a command.
Paths
Everything on disk has a path. An absolute path starts at the root of the file system (/ on macOS and Linux) and works from anywhere:
/Users/amira/projects/harbor-workshops/src/App.jsxA relative path starts from your current working directory:
src/App.jsxPath components and shell shortcuts express common locations:
| Symbol | Meaning | Example |
|---|---|---|
. |
The current directory | ./script.sh |
.. |
The parent directory | cd .. |
~ |
Your home directory | cd ~/projects |
/ |
The root (when leading) or a separator | /usr/bin |
Case sensitivity is a property of the file system and volume configuration. Linux file systems commonly distinguish App.jsx from app.jsx; macOS and Windows volumes often do not, although case-sensitive configurations exist. Match the exact filename case so imports remain portable.
2. Moving around
Three commands cover most navigation.
pwd # print working directory
# /Users/amira
ls # list the current folder
# Desktop Documents projects
ls -la projects # long format, including hidden files
cd projects # change directory
cd harbor-workshops
pwd
# /Users/amira/projects/harbor-workshops
cd .. # up one level
cd - # back to the previous directory
cd # with no argument: go homeFiles whose names start with a dot, such as .git, .gitignore, and .env, are hidden by default. ls -a (all) shows them. In a normal Git clone, .git is the directory holding local repository data. In a linked worktree it can instead be a file pointing to that data.
A name containing spaces must be quoted or escaped, otherwise the shell treats it as two arguments:
cd "My Projects" # quoted
cd My\ Projects # escapedThe simplest habit is to avoid spaces in project folder names and use kebab-case instead (harbor-workshops).
Speed tools
- Tab completion: type the first letters of a name and press Tab. The shell completes it or lists the possibilities. It saves typing and prevents typos.
- History: press the Up arrow to recall previous commands, or Ctrl+R to search them.
- Clear the screen:
clearor Ctrl+L. - Stop a running command: Ctrl+C. This is how you stop a development server.
3. Creating, copying, moving, and deleting
mkdir harbor-workshops # create a folder
cd harbor-workshops
mkdir -p src/components # -p creates parent folders as needed
touch README.md src/App.jsx # create empty files (or update timestamps)
cp README.md README.backup.md # copy a file
cp -r src src-copy # copy a folder (-r = recursive)
mv README.backup.md docs.md # rename (move within the same folder)
mv docs.md src/ # move into a folder
rm src/docs.md # delete a file
rm -r src-copy # delete a folder and its contentsTwo cautions deserve emphasis.
rmhas no recycle bin. A deleted file is gone, and it is not in the system trash.rm -rfrequests recursive deletion, suppresses confirmation, and ignores missing targets; it does not bypass filesystem permissions. A typo such asrm -rf ~ /tmp(note the space) can be catastrophic. Before deleting, runlson the same path to confirm what you are about to remove. A version previously committed to Git can normally be restored from available history; merely tracking a file does not preserve every uncommitted edit. Untracked files have no automatic Git recovery.mvandcpcan overwrite. Whether they prompt also depends on options, aliases, permissions, and the destination. For ordinary files,mv a.txt b.txtcan replace an existingb.txt. Use-i(interactive) to be asked first:cp -i,mv -i,rm -i.
mv is also the rename command. Some systems provide a separate rename utility, but its availability and syntax vary; mv is the common command used here.
4. Reading and searching text
cat package.json # print a whole file
less src/App.jsx # scroll a long file (q to quit, / to search)
head -n 5 src/App.jsx # first five lines
tail -n 20 server.log # last twenty lines
tail -f server.log # follow new lines as they are written
wc -l src/App.jsx # count linesgrep searches text for a pattern. It is the tool you will use most often to answer "where is this used?".
grep "bookSeats" src/App.jsx # lines containing bookSeats in one file
grep -r "bookSeats" src # search recursively through a folder
grep -rn "bookSeats" src # -n adds line numbers
grep -ri "capacity" src # -i ignores case
grep -rl "TODO" src # -l lists only file names
grep -rn --exclude-dir=node_modules "TODO" . # GNU grep option; check other versionsAlways exclude node_modules (or run the search inside src): it contains thousands of files and drowns real results.
find searches for files by name rather than content:
find src -name "*.test.js" # every Jest test file
find . -type d -name node_modules -prune -o -type f -name "*.jsx" -printIn unquoted ls src/*.jsx, the shell expands the wildcard. In find ... -name "*.jsx", quoting passes the pattern unchanged for find to interpret. The -prune example avoids descending into node_modules, rather than merely filtering its results afterward. No-match behavior of unquoted globs differs between Bash and zsh.
5. Pipes and redirection
Each program has three standard streams: input (stdin), output (stdout), and error (stderr). The shell lets you connect them.
>writes output to a file, overwriting it.>>appends output to a file.<reads input from a file.|(the pipe) sends one command's output to the next command's input.2>redirects error output.
ls src > files.txt # save the listing (overwrites files.txt)
echo "node_modules" >> .gitignore # append a line
grep -rn "TODO" src | wc -l # how many matching lines?
find docs -type f -name "*.md" # find Markdown filenames without parsing ls
npm test 2> errors.log # redirect stderr; stdout remains on screen
npm run build > build.log 2>&1 # both streams into one filePipes are why small commands are so powerful: each does one job, and you combine them. The shell also lets you chain commands with && (run the next only if the previous succeeded) and ; (run the next regardless):
npm run build && npm run preview # preview only if the build succeededRead $? immediately after a command to inspect its exit status. Zero normally means success; a nonzero value needs interpretation. For example, grep normally returns 1 for no matches, not an operational error.
By default a pipeline reports its final command’s status, so grep ... | wc -l can hide a search failure behind a successful count. Bash’s pipefail option changes this behavior, but also exposes normal no-match statuses; it is not a substitute for understanding each command. wc -l counts newline characters, not occurrences of a word.
Continue with browser and npm development workflow for related practice.
6. Environment, PATH, and permissions
Environment variables
An environment variable is a named value available to programs started from the shell.
printf '%s\n' "$HOME" # /Users/amira
printf '%s\n' "$SHELL" # configured login shell, not proof of the current shell
export API_URL="http://localhost:4000" # set for this session and child programs
printenv API_URLFront-end tools read variables for configuration. Vite exposes variables prefixed with VITE_ by default through import.meta.env; those user-defined values are strings and are normally replaced at build time. The prefix is configurable. Values can come from the environment and mode-specific .env files; never put secrets in anything that ships to the browser, because the browser bundle is public. Keep files containing private values out of Git, including local or mode-specific variants. A tracked .env.example should contain placeholders or public defaults, never private values.
PATH
When you type node, the shell does not search the whole disk. After shell syntax, aliases, functions, and builtins are considered, an external-command lookup searches the directories in PATH in order. Shells can cache the resolved executable path.
printf '%s\n' "$PATH"
# /usr/local/bin:/usr/bin:/bin:/Users/amira/.nvm/...
command -v node # how this shell resolves the name
node --versionThe error command not found: npm almost always means the program is not installed or its folder is not in PATH. command -v node and inspecting PATH are useful diagnostics. An external which implementation may not describe shell functions or aliases accurately. Version managers such as nvm work by changing PATH so that the chosen Node version is found first.
Permissions
On macOS and Linux each file has permissions for the owner, group, and others: read (r), write (w), and execute (x).
ls -l deploy.sh
# -rw-r--r-- 1 amira staff 210 Oct 16 09:00 deploy.shHere the owner can read and write, everyone else can only read, and nobody can execute. Running ./deploy.sh produces Permission denied. Assuming the script has a valid interpreter line, its parent directories are searchable, and the file system allows execution, add execute permission for its owner:
chmod u+x deploy.sh
./deploy.shDirectory permissions have distinct meanings: read lists names, write permits directory-entry changes, and execute permits traversal/search. ACLs, parent-directory access, and noexec mounts can also explain Permission denied; changing a file’s execute bit is not a universal fix.
Avoid the shortcut of running sudo npm install -g or sudo before everything. sudo normally runs as root unless another target user is selected; it can create root-owned files, which later causes EACCES errors for your normal user. Fix the permissions or the installation location instead.
7. Getting help
You do not need to memorize every flag.
ls --help # short built-in help (many Linux tools)
man grep # the manual page (q to quit)
npm help install
git help commit # you will use this in the next lessonOn macOS some commands do not support --help; use man. When you meet an unfamiliar error, read it from the top, copy the exact message into a search engine with the tool name, and check the official docs first.
Continue with Git snapshots, staging, and commits for related practice.
8. Worked example: prepare the Harbor Workshops project
Task. Use a new, empty practice folder for Harbor Workshops; these setup commands write files and should not be replayed over an existing project. Create the project folder, add the basic files, find every mention of "capacity" in a copied starter file, and prepare a repository-ready layout.
Step 1: Create the structure.
cd ~
mkdir -p projects
cd projects
mkdir -p harbor-workshops/src/components harbor-workshops/docs
cd harbor-workshops
pwd
# /Users/amira/projects/harbor-workshopsmkdir -p creates the intermediate folders in one command and does not fail if they already exist.
Step 2: Create files.
touch README.md src/App.jsx src/components/WorkshopCard.jsx
echo "# Harbor Workshops" > README.md
echo "node_modules" > .gitignore
echo ".env*" >> .gitignore
echo "!.env.example" >> .gitignore
echo "dist" >> .gitignore
cat .gitignore
# node_modules
# .env*
# !.env.example
# distCreate the promised npm manifest without installing packages:
cat > package.json <<'EOF'
{
"name": "harbor-workshops",
"version": "0.1.0",
"private": true,
"type": "module"
}
EOFThis manifest does not yet define a dev server or test command; later exercises add their tools and scripts.
Notice the first echo uses > because the file is new, and the others use >> to append. Using > for every entry would keep only the final line.
Step 3: Add a starter file and search it.
cat > src/components/WorkshopCard.jsx <<'EOF'
export default function WorkshopCard({ title, capacity, booked }) {
const seatsLeft = capacity - booked;
// TODO: show a warning when capacity is nearly reached
return <p>{title}: {seatsLeft} seats left (capacity {capacity})</p>;
}
EOF
grep -rn -i "capacity" src
# src/components/WorkshopCard.jsx:1:export default function WorkshopCard({ title, capacity, booked }) {
# src/components/WorkshopCard.jsx:2: const seatsLeft = capacity - booked;
# src/components/WorkshopCard.jsx:3: // TODO: show a warning when capacity is nearly reached
# src/components/WorkshopCard.jsx:4: return <p>...Step 4: Count and filter.
grep -rn "TODO" src | wc -l
# 1Step 5: Check the layout and hidden files.
ls -la
# Abbreviated names only; real -la output includes permissions, "." and "..":
# .gitignore README.md package.json docs srcWhy this approach and not others. The steps document how to reproduce this layout in a fresh folder. They are not an idempotent update script: repeated redirects can overwrite files or append duplicate entries. A graphical file manager also works; the command sequence makes the exact paths and operations easy to record. Using > for every line of .gitignore is wrong because each > overwrites the file. Searching with grep -r is better than opening every file in an editor because it shows all locations at once, with line numbers.
9. Comparison tables
Common commands by purpose
| Goal | Command | Notes |
|---|---|---|
| Where am I? | pwd |
Prints the absolute path |
| What is here? | ls, ls -la |
-a shows hidden files |
| Change folder | cd path |
cd .., cd ~, cd - |
| Make a folder | mkdir -p a/b |
-p for nested |
| Copy / move | cp, mv |
Can overwrite; -i requests confirmation |
| Delete | rm, rm -r |
No trash; verify first |
| Read a file | cat, less, head, tail |
less for long files |
| Search content | grep -rn |
Exclude node_modules |
| Search names | find |
Supports wildcards |
Redirection operators
| Operator | Effect | Typical risk |
|---|---|---|
> |
Write output to a file | Overwrites existing content |
>> |
Append output to a file | Duplicates lines if rerun |
| |
Send output to another command | Downstream commands can change files; upstream failures can be hidden |
2> |
Redirect stderr | Truncates the destination; if its parent is missing or inaccessible, redirection fails |
&& |
Run next only on success | Stops the chain at the first failure |
Absolute and relative paths
| Absolute | Relative | |
|---|---|---|
| Starts at | /; an unquoted ~ can expand to an absolute home path |
The current directory |
| Works from any folder | Yes | No |
| Best for | A fixed machine location independent of the working directory | Portable project paths resolved from a known project directory |
10. Pitfalls and study tips
- Pitfall: the wrong working directory. Many "it does not work" problems are simply running
npmorgitin the wrong folder. Runpwdandlsfirst. npm can search the current directory and ancestors for a project root; it does not search arbitrary child projects. Git also normally locates a repository through the current directory or its ancestors. - Pitfall: overwriting with
>. Use>>to append. A single wrong>can erase a configuration file. - Pitfall: deleting by wildcard.
rm *.jsremoves every matching file in the current folder. Preview the match withls *.jsbefore you delete. - Pitfall: spaces in paths. Quote them or avoid them.
- Pitfall:
sudoas a fix. It hides the real problem and creates root-owned files. - Pitfall: confusing the terminal and the shell. The terminal is the window; the shell interprets commands.
Study tip. For an original command-selection exercise, identify which operation achieves the stated goal. Identify the goal (navigate, create, move, search, combine) and then check the exact flag: -r for folders, -a for hidden files, -p for nested creation, >> to append. When two options look similar, ask "does this overwrite, delete, or ask first?"
Study tip. If a question shows command not found, think of PATH and installation. If it shows Permission denied, think of permissions and chmod. If it shows No such file or directory, check the path, the case, and the current directory.
Mini case study: the missing test file
Situation. Noor, a new teammate, runs npm test in her home folder and sees npm ERR! enoent Could not read package.json. She then runs ls, sees her project folder, and decides to fix it by running sudo npm install in her home folder. Later she wants to know which source files still contain console.log before a release.
Questions.
- What is the real cause of the first error?
- Why is
sudo npm installthe wrong response? - Write the commands to find every
console.loginsrcand count the files.
Solution.
- npm resolves the local project from the working directory and suitable ancestors. It will not find the child project merely because that folder is visible in
ls; Noor is outside it. The fix iscd projects/harbor-workshops(verified withpwdandls), thennpm test. sudodoes not solve a wrong-directory problem, and it would install packages into the wrong place as root, creating root-owned files that cause permission errors later.- Use
grep -rnF "console.log" srcfor locations andgrep -rlF "console.log" src | wc -lfor the number of matching filenames.-Ftreats the dot literally. This simple line count assumes filenames do not contain newlines; inspect stderr and search status if the result seems suspicious.
Key terms
- Terminal: the window that shows text input and output.
- Shell: the program that interprets your commands (bash, zsh, PowerShell).
- Path: the location of a file or folder; absolute or relative.
- Flag: an option that changes how a command behaves.
- Pipe (
|): connects one command's output to another's input. - Redirection: sending output to a file or reading input from one.
- Environment variable: a named value available to programs.
PATH: the ordered list of folders searched for commands.- Permission: the read, write, and execute rights of a file.
- Hidden file: a file whose name begins with a dot.
Summary checklist
- I can tell the terminal, the shell, and the file system apart.
- I can navigate with
pwd,ls,cd, and use.,.., and~. - I create files and folders with
mkdir -pandtouch. - I know that
rm,>,mv, andcpcan destroy data without warning. - I search with
grep -rnandfind, excludingnode_modules. - I can combine commands with pipes,
>,>>, and&&. - I can diagnose
command not foundwithPATHandPermission deniedwithchmod. - I keep secrets in
.envand out of version control. - I use tab completion, history, and
manto work faster.
Official sources
- Meta Front-End Developer Professional Certificate (opens in a new tab)
- Course 3: Version Control (opens in a new tab)
- GNU Bash Reference Manual (opens in a new tab)
- Pro Git: the command line (opens in a new tab)
- Vite: Env Variables and Modes (opens in a new tab)
- GNU Bash: Pipelines (opens in a new tab)
- GNU grep: Exit status (opens in a new tab)
- npm: Project folders (opens in a new tab)
- Apple: File-system formats (opens in a new tab)
