Course outline · 0% complete

0/29 lessons0%

Course overview →

Reading files: cat, less, head, tail

lesson 3-1 · ~10 min · 7/29

Recall from lesson 2-3 that touch report.txt creates an empty file when report.txt does not exist yet, and only refreshes the modified time when it does.

This lesson goes the other direction: putting text into files and reading it back out.

Putting text in, getting text out

Reading files without opening an editor is the daily bread of server work. A deploy fails, and the answer is sitting inside a log file on a machine with no desktop. These tools inspect any file straight from the prompt: a peek at the top, the newest lines at the bottom, or a full scroll through.

To have something to read, we first need files with content. The quickest way is echo "text" > file.txt, which saves echo's output into a file instead of printing it. That > arrow is redirection, and >> appends to the end rather than overwriting. Unit 5 covers both in depth, so for now it is just a way to fill a file.

The reading tools, smallest output to largest:

CommandShows
cat fileThe whole file at once. Short for concatenate, since it can print several files back to back.
head -n 5 fileOnly the first 5 lines.
tail -n 5 fileOnly the last 5 lines, which is where the newest log entries live.
less fileThe file in a scrollable reader, for anything long. Same keys as man in lesson 1-3: space pages down, q quits.

Filling a file with > and >>

Three echo lines build a shopping list. The first uses > to create the file, and the next two use >> to append, then cat prints the finished result.

echo "milk" > shopping.txt
echo "bread" >> shopping.txt
echo "coffee" >> shopping.txt
cat shopping.txt

Output

milk
bread
coffee

The distinction between the two arrows is the whole point of the example. Using > on every line would overwrite the file each time, so only the last value, coffee, would survive. > starts a file, >> grows it.

Numbering lines with cat -n

One more cat flag earns its keep: -n numbers each output line. When an error message refers to "line 2", this is how you find line 2 without counting by hand.

echo "milk" > list.txt
echo "eggs" >> list.txt
echo "bread" >> list.txt
cat -n list.txt

Output

     1	milk
     2	eggs
     3	bread

The numbers are added by cat as it prints and are not part of the file itself. The file still holds three plain lines of text, which is worth remembering before piping numbered output into another tool.

Peeking at both ends of a long file

head and tail come into their own on files too big to read. seq 1 100 prints the numbers 1 through 100, and redirection saves all of them into numbers.txt.

seq 1 100 > numbers.txt
head -n 3 numbers.txt
tail -n 2 numbers.txt

Output

1
2
3
99
100

Five lines of output from a hundred-line file: head -n 3 supplies the first three and tail -n 2 the last two. Neither command reads or prints the 95 lines in the middle, which is exactly why they stay fast on enormous files.

For a two-million-line server log where the newest errors are at the end, tail -n 20 log.txt is the right tool. tail reads from the end of the file, which is where the most recent entries are appended.

The alternatives fail for opposite reasons. cat would dump all two million lines into the terminal, burying the interesting part in a wall of scroll. head would show the oldest lines in the file, which are the least likely to explain a failure that just happened.

The same three tools combine to sample any generated range. seq 10 20 produces the numbers 10 through 20, > captures them into range.txt, and then head and tail read the two ends of the saved file.

seq 10 20 > range.txt
head -n 2 range.txt
tail -n 1 range.txt

Output

10
11
20

The output is exactly the requested slices: head -n 2 gives 10 and 11 from the top, and tail -n 1 gives the single last line, 20. The eight lines in between stay in the file, untouched and unprinted.