The terminal looks unwelcoming because it tells you nothing about what it can do. Everything else on this site assumes you are comfortable there; this page is how you get comfortable. It covers moving around, working with files, wildcards, quoting, pipes and redirection — which together account for most of what anyone does at a shell.
Reading the prompt
kevin@server:~/projects$
│ │ │ └─ $ means a normal user; # means root
│ │ └───────── where you are (~ is your home directory)
│ └─────────────── which machine
└───────────────────── who you areThat # is worth noticing. It means you are root, and nothing will ask you whether you meant it.
A command is a name followed by options and arguments:
ls -la /var/log
│ │ └─ argument: what to act on
│ └───── options: short form, combinable
└──────── the commandShort options use one dash (-l) and can be bundled (-la). Long options use two (--all) and cannot.
Where you are, and getting elsewhere
pwd # print working directory — where am I
ls # what is here
ls -l # long format: permissions, owner, size, date
ls -la # include hidden files (names beginning with a dot)
ls -lh # human-readable sizes
cd /var/log # go somewhere absolute
cd projects # go somewhere relative to here
cd .. # up one level
cd ~ # home
cd - # back to where you just werePaths come in two kinds, and the distinction matters more than anything else on this page:
| Path | Means |
|---|---|
/etc/nginx | Absolute — starts at the root, means the same thing everywhere |
nginx/conf | Relative — from wherever you currently are |
~ | Your home directory, e.g. /home/kevin |
. | The current directory |
.. | The directory above |
- | (with cd) the previous directory |
A leading / is the whole difference. cd /home goes to the system’s home directory; cd home looks for one inside where you already are and usually fails.
Looking at files without opening an editor
cat file.txt # print the whole thing
less file.txt # page through it: q quits, / searches
head file.txt # first 10 lines
head -20 file.txt # first 20
tail file.txt # last 10 lines
tail -f app.log # follow it live as it grows
wc -l file.txt # count lines
file something # what kind of file is thisless is the one to reach for by default. cat on a large file floods your terminal, and on a binary file it can leave the display in a mess — reset fixes that if it happens.
tail -f is how you watch a log while reproducing a problem. Ctrl-C stops it. To edit rather than read, see vim and nano.
Creating, copying, moving, deleting
mkdir notes # make a directory
mkdir -p a/b/c # make parents as needed
touch file.txt # create an empty file
cp file.txt copy.txt # copy
cp -r dir/ backup/ # copy a directory and its contents
cp -i file.txt copy.txt # ask before overwriting
mv old.txt new.txt # rename
mv file.txt ~/documents/ # move
rm file.txt # delete a file
rmdir empty-dir # delete an empty directory
rm -r dir/ # delete a directory and everything in itThere is no undo and no recycle bin. rm unlinks the file and the space is reused. Recovery is a specialist job with poor odds, so treat every rm as final.
Three habits that prevent nearly all of the damage:
- List before you delete. Run
lswith the same pattern first and read what comes back. The find page makes the same point about-delete. - Be wary of
rm -rfwith a variable or a wildcard. A trailing space or an empty variable turns a targeted delete into a very broad one. - Use
-iwhen it matters.cp -iandmv -iask before overwriting; without them they overwrite silently.
Note that mv to an existing filename replaces it without a word. That is the most common way people lose a file they meant to keep.
Wildcards
The shell expands these before the command runs. The command never sees the pattern — it sees the list of matching filenames.
| Pattern | Matches |
|---|---|
* | Any characters, including none |
? | Exactly one character |
[abc] | One character from the set |
[0-9] | One character from the range |
{a,b} | Each alternative in turn |
ls *.txt # every .txt file
ls report-?.pdf # report-1.pdf, report-a.pdf
ls log-[0-9]*.txt # log-1.txt, log-2024.txt
cp file.{txt,bak} # expands to: cp file.txt file.bak
ls .* # hidden filesBecause expansion happens first, echo is a free preview. Put echo in front of any command you are unsure about and the shell shows you exactly what it would have run:
echo rm *.logThis one habit will save you at some point.
Quoting, and why spaces break everything
The shell splits on spaces. rm my file.txt is two arguments, so it tries to delete my and file.txt.
rm "my file.txt" # quoted — one argument
rm my\ file.txt # or escape the spaceThe two kinds of quote behave differently, and this catches people out for years:
name="Kevin"
echo "Hello $name" # Hello Kevin — double quotes expand variables
echo 'Hello $name' # Hello $name — single quotes are literal- Double quotes keep the text together but still expand
$variables, backticks and$(commands). - Single quotes mean exactly what is written, with no expansion at all.
Which is why patterns for grep, sed and awk go in single quotes — those tools have their own meaning for $ and *, and single quotes stop the shell interfering first.
And in scripts, quote your variables: rm "$file", not rm $file. Unquoted, a filename with a space becomes two arguments and an empty variable disappears entirely.
Pipes and redirection
This is the idea that makes the command line worth learning. Every program has three channels: input, output, and errors. You can rewire all three.
| Symbol | Does |
|---|---|
> | Send output to a file, replacing it |
>> | Send output to a file, appending |
< | Take input from a file |
2> | Redirect errors only |
2>&1 | Send errors to the same place as output |
| | Feed one command’s output into the next |
ls > files.txt # save the listing (overwrites!)
ls >> files.txt # add to it
command 2> errors.txt # errors to a file, output to screen
command > out.txt 2>&1 # everything to one file
command > /dev/null 2>&1 # discard everything
cat access.log | grep "404" | wc -l # count 404s
ps aux | grep nginx # find a process
du -h /var | sort -h | tail -10 # ten biggest things in /var
history | grep ssh # what did I type beforeTwo things worth internalising. > truncates the file immediately, before the command even runs — so sort file.txt > file.txt empties it. And 2>&1 must come after the redirect: > out.txt 2>&1 works, 2>&1 > out.txt does not.
tee is the useful middle ground — write to a file and keep showing it:
command | tee output.txt
command | tee -a output.txt # append insteadGetting help
man ls # the manual: q quits, / searches
ls --help # usually shorter and more readable
apropos network # search manual descriptions by keyword
which python3 # where is this command
type ll # is it a command, an alias, or a function
tldr tar # practical examples — needs installing, worth itMan pages are references rather than tutorials, which is why they feel unhelpful at first. Skip to the EXAMPLES section at the bottom — /EXAMPLES then Enter jumps there.
Shortcuts that change how it feels
| Key | Does |
|---|---|
| Tab | Complete a command or filename. Twice shows the options. |
| Up / Down | Previous commands |
| Ctrl-R | Search your history — type a fragment, press again to cycle |
| Ctrl-C | Stop what is running |
| Ctrl-D | End of input, or log out |
| Ctrl-L | Clear the screen |
| Ctrl-A / Ctrl-E | Jump to start / end of the line |
| Ctrl-U / Ctrl-K | Delete to start / end of the line |
!! | The previous command — sudo !! re-runs it with sudo |
Tab completion is not a convenience, it is a correctness tool. If Tab does not complete a path, the path is wrong — you have caught a typo before running anything. Experienced users type very few filenames in full.
Ctrl-R is the other one worth building a habit around. Most of what you need to type, you have typed before.
Things that confuse everyone at first
- Nothing happened. Silence means success. Unix commands report problems and stay quiet otherwise.
- The password prompt shows nothing. It is being typed; the characters are simply not echoed. Type it and press Enter.
- Case matters.
File.txtandfile.txtare different files, and-rand-Rare often different options. - Spaces in filenames are trouble. Legal, but they require quoting everywhere. Underscores and hyphens save effort.
- The terminal froze. You probably pressed Ctrl-S, which is flow control. Ctrl-Q unfreezes it.
- A stray quote. A prompt showing
>means the shell is waiting for you to close a quote. Ctrl-C escapes. - Permission denied. Either you need sudo, or the permissions are wrong. Do not reflexively add sudo — understand which it is first.
Where to go next
With the above you can navigate a system and read what is on it. The natural next steps:
- File permissions — the thing that most often stops a beginner in their tracks.
- grep and find — searching inside files, and for files.
- vim and nano — editing, and getting out of vim.
- ssh — doing all of this on a machine somewhere else.
- The full command reference — when you know what you want and need the flags.
Quick reference
pwd ls -la cd .. cd ~ cd - # where am I, what is here, move
cat less head tail -f wc -l # look at files
mkdir -p touch cp -r mv rm -r # create, copy, move, delete
* ? [0-9] {a,b} # wildcards
echo rm *.log # preview what a wildcard matches
"$var" '$literal' # double expands, single does not
cmd > file cmd >> file # redirect output (> overwrites)
cmd 2> err cmd > all 2>&1 # redirect errors
cmd1 | cmd2 cmd | tee file # pipe, and pipe-plus-save
man cmd cmd --help which cmd # help
Tab Ctrl-R Ctrl-C Ctrl-L !! # the shortcuts that matter