Shell Basics
Navigation, file ops, pipes, redirection, env vars.
The terminal looks intimidating from the outside and then you spend a week with it and realize it's just a chat window where the other side happens to be your computer. Every senior dev lives here. By the end of this lesson you'll know the dozen commands that cover 90% of what they do.
Where am I? pwd, cd, ls
A shell session is always "in" some directory, called the working directory. Three commands are your compass:
pwd
# /Users/ada/projects/website
ls
# index.html src package.json README.md
cd src
pwd
# /Users/ada/projects/website/src
cd .. # go up one level
cd ~ # go to your home directory
cd - # go back to the previous directorylson its own shows a tidy list. The flag combo you'll type a thousand times is ls -la: long format, including hidden files (the ones that start with a dot).
ls -la
# total 32
# drwxr-xr-x 6 ada staff 192 May 24 10:11 .
# drwxr-xr-x 9 ada staff 288 May 24 09:55 ..
# -rw-r--r-- 1 ada staff 34 May 24 10:00 .env
# -rw-r--r-- 1 ada staff 220 May 24 10:11 .gitignore
# drwxr-xr-x 5 ada staff 160 May 24 10:08 src
# -rw-r--r-- 1 ada staff 512 May 24 10:11 package.jsonThe leftmost column is the permissions string. d means directory, then three sets of rwxfor owner, group, and everyone. You'll learn to skim it.
. are hidden by convention only. They contain config (.zshrc, .gitignore, .env). There's no magic, just a filename starting with a dot.Moving stuff around: cp, mv, rm, mkdir
mkdir notes # create a directory
mkdir -p a/b/c # create nested dirs in one shot
cp index.html backup.html # copy file
cp -r src/ src-backup/ # copy directory recursively
mv old.txt new.txt # rename
mv draft.md notes/ # move into a directory
rm old.log # delete a file
rm -r build/ # delete a directory and contentsrm. Once it's gone, it's gone. And rm -rf / will try to delete everything on your computer. Never paste an rmcommand you don't fully understand.Reading files: cat, less
catdumps a file's contents to the terminal. Great for short files, awful for huge ones (you'll scroll forever).
cat package.json
# {
# "name": "website",
# "version": "1.0.0",
# "scripts": { "dev": "next dev" }
# }For big files use less. It pages through one screen at a time. Arrows to scroll, / to search, q to quit.
less server.log
# (use arrows, page-down, /pattern to search, q to quit)Environment variables and $PATH
Environment variables are named values your shell knows about. Programs read them to pick up config (API keys, locales, paths). Set, read, list:
export NAME="Ada" # set for this session and children
echo $NAME # Ada
env # list all variables
env | grep PATH # filter to PATH-related onesThe most important variable is $PATH. It's a list of directories the shell searches when you type a command. When you run git status, your shell looks through every directory in $PATH until it finds an executable named git.
echo $PATH
# /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin
which git
# /opt/homebrew/bin/git
which -a node
# /Users/ada/.nvm/versions/node/v22.0.0/bin/node
# /opt/homebrew/bin/node (an older one earlier in PATH wins)$PATH. Add it to your shell config.Your shell config: .zshrc / .bashrc
Every time you open a new terminal, the shell runs a startup script. That's where you set $PATH, define aliases, and tweak the prompt. macOS defaults to zsh, so the file is ~/.zshrc. Linux often defaults to bash and ~/.bashrc.
# add Homebrew to PATH
export PATH="/opt/homebrew/bin:$PATH"
# a couple of useful aliases
alias ll="ls -la"
alias gs="git status"
alias ..="cd .."
# a prompt with the current directory and git branch
export PS1="%~ %# "After editing, either open a new terminal or run source ~/.zshrc to apply changes to your current session.
history: rerun and search past commands
history | tail -20
# 998 git status
# 999 npm run dev
# 1000 history | tail -20
!! # re-run the last command
!999 # re-run command 999
sudo !! # re-run last with sudo
^old^new # re-run last, replacing 'old' with 'new'Press Ctrl-R and start typing. The shell does a fuzzy search through your history. This is one of those tricks that, once you know it, you use 30 times a day.
Modern upgrades worth knowing
The classics above are universal. But a few modern tools dramatically speed up your workflow:
- zoxide - a smarter
cd. Learns the directories you visit and jumps to them by partial name.z webbeams you to~/code/personal/web-development. - fzf - fuzzy finder. Press
Ctrl-Rwith fzf installed and history becomes interactive. Pipe anything intofzfto pick from it. - eza / bat - prettier
lsandcatwith icons and syntax highlighting. - starship - a fast, customizable prompt that shows git status, runtime versions, and more.
Ctrl-R. It pays for itself in a single afternoon of debugging.Quick quiz
What does ls -la show that ls does not?
Recap
pwd,cd,ls -laare your navigation core.cp,mv,rm,mkdirmove and reshape files.rm -rfis permanent.$PATHis the list of directories your shell searches for commands.- Customize
~/.zshrcor~/.bashrcfor aliases and PATH tweaks. Ctrl-Rsearches your history. Install fzf to supercharge it.