Module 2: Working with Files and Text
4. Reading files: cat, less, head, and tail
Description
By the end of this lesson you will be able to choose, without hesitation, which tool to use to read any text file — from a ten-line configuration file to a million-line production log — and you will be able to follow that log as it grows, in real time, with nothing to refresh by hand.
This is not a terminal-trivia exercise. Checking logs is probably the most repeated task in any job involving backend, infrastructure, or data: a service fails and the first move for someone with experience is to open a terminal and look at the log, not a dashboard. Choosing the right tool based on the file's size — and not leaving your own terminal unusable by picking the wrong one — is the difference between diagnosing an incident in thirty seconds or fighting your own screen for ten minutes.
Connection to the module: you already know how to create structure with mkdir and touch, and how to move, copy, and delete applying explicit safety judgment. You were missing the piece that connects to what follows: looking at the real content of those files. Without this, find — the next lesson — is only going to tell you where a file is, never what is inside it.
The real criterion: the file's size decides
When someone sends you a three-line message, you read it all in one glance. When you get handed a three-hundred-page file, you do not read it from page one to the last without stopping: you check the index, jump to the chapter that interests you, and if you need to find a specific word you do not flip page by page, you search for it. The terminal has a tool for each of those gestures, and choosing wrong is not a style mistake: with a large file it can leave your terminal stuck for several seconds printing text you are never going to read, or make you lose track of exactly the data you were looking for among thousands of lines that flew by.
Before deciding, you measure. wc (word count) with the -l flag counts lines without showing you a single one:
wc -l file.txt
With that number in hand, the criterion is simple:
- Few lines (everything fits on one screen):
catdumps it whole and you are done. - Many lines:
lessopens it as a real viewer, loading it in chunks, with navigation and search. - You only care about one end (the beginning or the end, no matter the size):
headortail.
Worked example
Start with a short file. Create it with real content using echo and the >> operator (appends a line to the end of a file without erasing what was already there; it is a redirection operator you are going to study in depth in the pipes and redirection module — here we just use it to have an example file):
echo "Review Friday's deploy" >> notes.txt
echo "Request access to the staging database" >> notes.txt
echo "Confirm meeting with the data team" >> notes.txt
Measure before opening:
wc -l notes.txt
What to expect:
3 notes.txt
Three lines fit on any screen, so cat (from concatenate: join and dump) is exactly the right tool:
cat notes.txt
What to expect:
Review Friday's deploy
Request access to the staging database
Confirm meeting with the data team
Now the other extreme. Most Unix systems (macOS and many Linux distributions) ship a file with a word list at /usr/share/dict/words, originally meant for the system's spell checker. It is perfect as a real "large" file, with nothing for you to fabricate. Measure first:
wc -l /usr/share/dict/words
What to expect: a number in the hundreds of thousands (the exact value varies depending on your operating system and its version; it is not the number that matters, but the order of magnitude). If your machine does not have that file, replace it in the examples below with any long text file you have on hand: a real log, a large CSV, or your shell history (~/.zsh_history or ~/.bash_history).
If you ran cat /usr/share/dict/words right now, hundreds of thousands of lines would fly past your screen in a second, and you would end up seeing only the last screenful, with no way to go back to the beginning short of running the command again. That is the typical misuse of cat: using it as if it were a viewer when the file is not short. With a truly large file — a million-line log, for example — the terminal on top of that can sit "thinking" for several seconds, printing text you are not going to read.
That is exactly what less exists for: a real viewer, that loads the file in chunks instead of dumping it whole.
less /usr/share/dict/words
Inside less, navigation is with keys, not the mouse:
| Key | Action |
|---|---|
Space or f | advance one screen |
b | go back one screen |
g | jump to the first line |
G | jump to the last line |
/pattern + Enter | search forward |
?pattern + Enter | search backward |
n | repeat the search in the same direction |
N | repeat the search in the opposite direction |
q | quit the viewer |
Try a real search: inside less, type /terminal and press Enter. What to expect: the cursor jumps to the first line containing that word and highlights it; if you press n, it jumps to the next match (there can be several related entries, like compound words). Press q when you are done: you leave the viewer and return exactly to your terminal prompt, with the window never having closed and your session never lost.
If you want to see the line numbers from the moment you open the file (useful for referencing an exact line later), start it with -N:
less -N /usr/share/dict/words
What to expect: every line with its number in the left margin, something like this at the start of the file:
1 A
2 a
3 aa
4 aal
5 aalii
Finally, if you only care about one end and do not need to navigate anything in the middle, head and tail give it to you without opening the whole file:
head -n 5 /usr/share/dict/words
tail -n 5 /usr/share/dict/words
What to expect: head -n 5 shows the first five lines (given the file's alphabetical order, short entries like the ones in the table above); tail -n 5 shows the last five (words starting with the last letters of the alphabet). Without the -n flag, both commands show 10 lines by default — that value does not depend on the file's size, it is a fixed default of the tool.
Following a file live: tail -f
Everything above assumes a still file, one that already finished being written. But a running service's log keeps getting written to while you look at it. That is what a tail flag you are going to use for the rest of your career exists for: -f, for follow.
Open two terminal tabs or windows pointing at the same folder. In the first one (call it A):
touch app.log
tail -f app.log
The terminal does not hand you back the prompt: it just sits there, waiting. That is exactly what -f does — instead of showing the last lines and exiting like a normal tail -n would, it stays watching the file and shows you every new line the moment it gets written, with nothing to run again.
In the second tab (B), in the same folder, simulate a new log line:
echo "2026-07-21 10:03:12 INFO server started" >> app.log
Go back to tab A. What to expect: without you touching anything there, the new line showed up on its own:
2026-07-21 10:03:12 INFO server started
Repeat in tab B with another line:
echo "2026-07-21 10:03:45 ERROR connection refused" >> app.log
And in tab A that line also shows up instantly, with nothing done on your end. To stop following, Ctrl+C — it hands back tab A's prompt.
This is, literally, how you are going to diagnose most production incidents: you leave tail -f running on the service's log while you reproduce the bug or wait for it to happen, and you watch the errors show up the exact moment they occur.
What happens if you open a binary (and how to get your terminal back)
Not every file is text. A compiled binary, an image, a .zip, contain bytes that are not printable characters. If you accidentally run cat on one of these:
cat /bin/ls
What to expect: a screen full of strange symbols and, in the worst case, your terminal changes behavior — the text you type afterward is not visible, or the colors come out wrong. This happens because the binary's bytes include escape sequences (control codes programs use, for example, to change text color in the terminal), and the terminal interprets them literally, ending up with its configuration altered.
The terminal is not actually broken, and the fix is not closing the window: it is the reset command.
reset
Type it even if you cannot see what you are typing — sometimes the terminal gets so confused that even keyboard echo stops working — and press Enter. reset reinitializes the terminal to its default configuration: it recovers keyboard echo, normal line mode, and special characters. You are going to lose your scrollback history, but the terminal becomes usable again.
Common mistakes
Thinking cat is a viewer. cat was designed to concatenate and dump files to standard output as fast as possible, not to paginate or navigate — that misunderstanding is what leads to running it on a million-line file and getting stuck with a jammed terminal. You spot it when, after a cat, you can only see the last screenful and there is no way back without running the command again. You fix it by measuring first with wc -l and using less (or head/tail) the moment the file does not fit whole on one screen.
Believing tail -f hung. If you run tail -f and the prompt does not come back, it is tempting to think the command failed or the terminal froze. In reality that is its correct behavior: it is waiting for new writes to the file, indefinitely, until you decide to stop. You spot it because Ctrl+C does respond right away (if the terminal were truly stuck, it would not respond to that either). You fix it with Ctrl+C to stop following and get the prompt back.
Assuming the default 10 lines are the whole file. Running head or tail with no -n and assuming the file ends there is a common mistake when someone does not know 10 is a fixed default of the tool, not a reflection of the file's actual size. You spot it by comparing against wc -l: if head (no flag) shows 10 lines but wc -l says 50,000, there are 49,990 lines you did not see. You fix it by using -n with the number you need, after measuring with wc -l.
Exercises
Exercise 1 — Measure and decide. You have a file called sales-data.csv in your current folder and do not know how many lines it has. What command do you run to find out before deciding how to open it? If the result is 40, which tool would you use to read it whole? If the result is 800,000, which one would you use, and why not cat?
See solution
wc -l sales-data.csv
With 40 lines: cat sales-data.csv — fits whole on one screen, nothing to navigate.
With 800,000 lines: less sales-data.csv (or head/tail if you only need one end). cat would dump all 800,000 lines at once, leaving you only the last screenful visible with no way back; less loads the file in chunks and lets you navigate and search without printing it all at once.
Exercise 2 — Navigate with less. Open /usr/share/dict/words with line numbers visible from the start, without having to turn them on afterward. Jump straight to the file's last line. Search for the word "terminal" and then exit the viewer without closing your terminal window.
See solution
less -N /usr/share/dict/words
Inside the viewer: G (jumps to the end of the file), ?terminal + Enter (searches backward, because you are already at the end — if you searched with / from there, there would be nothing ahead to find), and q to quit.
Why it works: -N turns on line numbers at startup instead of having to reopen the file with another flag; G takes you to the end of the file with a single key; ? searches backward from your current position (while / searches forward); q closes the viewer without affecting your terminal session in any way.
Exercise 3 — head and tail with -n. A server.log file has 50,000 lines. You want to see only the first 3 (to confirm when the service started) and the last 3 (to see its most recent state), without opening the whole file. Write the two commands.
See solution
head -n 3 server.log
tail -n 3 server.log
Why it works: -n 3 explicitly tells each command how many lines to show, instead of accepting the default (10). head counts from the start of the file and tail from the end, and neither one needs to load all 50,000 lines to do it.
Exercise 4 — Troubleshooting. You accidentally ran cat on a .png file and now your terminal shows strange symbols; when you type, you cannot see what you are typing. What do you do?
See solution
reset
Type it and press Enter, even if you cannot see the keys on screen while you do it.
Why it works: reset reinitializes the terminal's configuration to its default values — it recovers keyboard echo and normal line mode that the binary's escape sequences had altered. It does not delete any file or close your session, it only repairs the terminal's state.
Summary and next step
Before moving on you should be able to:
- Measure a file with
wc -lbefore deciding how to open it. - Choose
catfor short files andlessfor long ones, without hesitation. - Navigate inside
less: forward, backward, jump to the start and end, search with/and?, and quit withq. - Use
head -nandtail -nto peek at a file's ends without opening it whole. - Leave
tail -frunning to follow a file that keeps growing, and knowCtrl+Cstops it. - Recover your terminal with
resetif you opened a binary by mistake.
Everything you did today assumes you already knew where the file was: you wrote it yourself with touch, or someone gave you the exact name and full path. In a real project, with thousands of files spread across dozens of folders, that assumption falls apart — you are going to need to ask the filesystem "where is this?" before you can read it with any of these tools. That is the missing piece, and it is exactly what find solves.
Resources
- cat invocation — GNU Coreutils Manual — official reference for
cat's options. - head invocation — GNU Coreutils Manual — all of
head's flags, including the difference between-n(lines) and-c(bytes). - tail invocation — GNU Coreutils Manual — details
-fversus-Ffor logs that rotate files. - wc invocation — GNU Coreutils Manual — all of
wc's metrics, not just-l. - less(1) — Linux manual page — full list of navigation and search commands inside
less. - reset(1) — ncurses-bin, Debian Manpages — exactly what
resetdoes and its relationship totset.