Viewing Part or Whole File Contents

In this chapter, you'll learn how to view contents of files from within the terminal. If the contents are too long, you can choose to view one screenful at a time or get only the starting/ending portions of the input. The commands used for these purposes also have other functionalities, some of which will be discussed in this chapter as well.

info The example_files directory has the sample input files used in this chapter.

cat

The cat command derives its name from concatenate. It is primarily used to combine the contents of multiple files to be saved in a file or sent as input to another command.

Commonly used options are shown below:

  • -n prefix line number and a tab character to each input line
  • -b like -n but doesn't number empty lines
  • -s squeeze consecutive empty lines to a single empty line
  • -v view special characters like NUL using the caret notation
  • -e view special characters as well as mark the end of line
  • -A includes -e and also helps to spot tab characters

Here are some examples to showcase cat's main utility. One or more files can be given as arguments.

info As mentioned earlier, the example_files directory has the sample input files used in this chapter. You need to cd into the example_files/text_files directory to follow along the examples shown in this chapter.

# view contents of a single file
$ cat greeting.txt
Hi there
Have a nice day

# another example
$ cat fruits.txt
banana
papaya
mango

# concatenate multiple files
$ cat greeting.txt fruits.txt
Hi there
Have a nice day
banana
papaya
mango

To save the output of concatenation, use redirection:

$ cat greeting.txt fruits.txt > op.txt

$ cat op.txt
Hi there
Have a nice day
banana
papaya
mango

You can represent stdin data using - as a file argument. If file arguments are not present, cat will read from stdin data if present or wait for interactive input. Note that - is also supported by many more commands to indicate stdin data.

# concatenate contents of 'greeting.txt' and 'stdin' data
$ echo 'apple banana cherry' | cat greeting.txt -
Hi there
Have a nice day
apple banana cherry

info Using cat to view the contents of a file, to concatenate them, etc is well and good. But, using cat when it is not needed is a bad habit that you should avoid. See wikipedia: UUOC and Useless Use of Cat Award for more details.

cat also helps you spot special characters using the caret notation:

# example for backspace and carriage return characters
$ printf 'car\bd\nbike\rp\n'
cad
pike
$ printf 'car\bd\nbike\rp\n' | cat -v
car^Hd
bike^Mp

# example with tab characters and end-of-line marker
$ printf '1 2\t3\f4\v5   \n' | cat -A
1 2^I3^L4^K5   $

tac

You can concatenate files using tac as well, but the output will be printed in the reverse (line wise). If you pass multiple input files, each file content will be reversed separately. Here are some examples:

$ printf 'apple\nbanana\ncherry\n' | tac
cherry
banana
apple

# won't be same as: cat greeting.txt fruits.txt | tac
$ tac greeting.txt fruits.txt
Have a nice day
Hi there
mango
papaya
banana

warning If the last line of input doesn't end with a newline, the output will also not have that newline character.

$ printf 'apple\nbanana\ncherry' | tac
cherrybanana
apple

less

The cat command is not suitable for viewing contents of large files in the terminal. The less command automatically fits the content to the size of the terminal, allows scrolling and has nifty features for effective viewing. Typically, the man command uses less as the pager to display the documentation. The navigation options are similar to the Vim text editor.

Commonly used commands are given below. You can press the h key for builtin help.

  • and arrow keys to move up and down by a line
    • you can also use k and j keys (same keys as those used by the Vim text editor)
  • f and b keys to move forward and backward by a screenful of content
    • Space key also moves forward by a screen
  • mouse scroll moves up and down by a few lines
  • g or Home go to the start of the file
  • G or End go to the end of the file
  • /pattern followed by Enter search for the given pattern in the forward direction
    • pattern refers to regular expressions and depends on the regex library in your system
    • the flavor is Extended Regular Expressions (ERE) on my system
    • see man re_format for more details
  • ?pattern followed by Enter search for the given pattern in the backward direction
  • n go to the next match
  • N go to the previous match
  • q quit

As an example, use less /usr/share/dict/words to open a dictionary file and practice the commands discussed above. If your pager is set to less for manual pages, you can also try something like man ls for practice.

Similar to the cat command, you can use the -s option to squeeze consecutive blank lines. But unlike cat -n, you need to use less -N to prefix line numbers. The lowercase -n option will turn off numbering.

Further Reading

tail

By default, tail displays the last 10 lines of input files. If there are less than 10 lines in the input, only those lines will be displayed. You can use the -n option to change the number of lines displayed. By using tail -n +N, you can get all the lines starting from the Nth line.

Here's an example file that'll be used for illustration purposes:

$ cat sample.txt 
 1) Hello World
 2) 
 3) Hi there
 4) How are you
 5) 
 6) Just do-it
 7) Believe it
 8) 
 9) banana
10) papaya
11) mango
12) 
13) Much ado about nothing
14) He he he
15) Adios amigo

Here are some examples with the -n option:

# last two lines (input has 15 lines)
$ tail -n2 sample.txt
14) He he he
15) Adios amigo

# all lines starting from the 11th line
# space between -n and +N is optional
$ tail -n +11 sample.txt
11) mango
12) 
13) Much ado about nothing
14) He he he
15) Adios amigo

If you pass multiple input files, each file will be processed separately. By default, the output is nicely formatted with filename headers and empty line separators which you can override with the -q (quiet) option.

$ tail -n2 fruits.txt sample.txt 
==> fruits.txt <==
papaya
banana

==> sample.txt <==
14) He he he
15) Adios amigo

The -c option works similar to the -n option, but with bytes instead of lines:

# last three bytes
# note that the input doesn't end with a newline character
$ printf 'apple pie' | tail -c3
pie

# starting from the fifth byte
$ printf 'car\njeep\nbus\n' | tail -c +5
jeep
bus

Further Reading

By default, head displays the first 10 lines of input files. If there are less than 10 lines in the input, only those lines will be displayed. You can use the -n option to change the number of lines displayed. By using head -n -N, you can get all the input lines except the last N lines.

# first three lines
$ head -n3 sample.txt
 1) Hello World
 2) 
 3) Hi there

# except the last 11 lines
$ head -n -11 sample.txt
 1) Hello World
 2) 
 3) Hi there
 4) How are you

You can select a range of lines by combining both the head and tail commands.

# 9th to 11th lines
# same as: tail -n +9 sample.txt | head -n3
$ head -n11 sample.txt | tail -n +9
 9) banana
10) papaya
11) mango

If you pass multiple input files, each file will be processed separately. By default, the output is nicely formatted with filename headers and empty line separators which you can override with the -q (quiet) option.

$ printf '1\n2\n' | head -n1 greeting.txt -
==> greeting.txt <==
Hi there

==> standard input <==
1

The -c option works similar to the -n option, but with bytes instead of lines:

# first three bytes
$ printf 'apple pie' | head -c3
app

# excluding the last four bytes
$ printf 'car\njeep\nbus\n' | head -c -4
car
jeep

Exercises

info Use the example_files/text_files directory for input files used in the following exercises.

1) Which option(s) would you use to get the output shown below?

$ printf '\n\n\ndragon\n\n\nunicorn\n\n\n' | cat # ???

     1  dragon

     2  unicorn

2) Pass appropriate arguments to the cat command to get the output shown below.

$ cat greeting.txt
Hi there
Have a nice day

$ echo '42 apples and 100 bananas' | cat # ???
42 apples and 100 bananas
Hi there
Have a nice day

3) Will the two commands shown below produce the same output? If not, why not?

$ cat fruits.txt ip.txt | tac

$ tac fruits.txt ip.txt 

4) Go through the manual for the tac command and use appropriate options and arguments to get the output shown below.

$ cat blocks.txt
%=%=
apple
banana
%=%=
brown
green

# ???
%=%=
brown
green
%=%=
apple
banana

5) What is the difference between less -n and less -N options? Does cat -n and less -n have similar functionality?

6) Which command would you use to open another file from within an existing less session? And which commands would you use to navigate between previous and next files?

7) Use appropriate commands and shell features to get the output shown below.

$ printf 'carpet\njeep\nbus\n'
carpet
jeep
bus

# use the above 'printf' command for input data
$ c=# ???
$ echo "$c"
car

8) How would you display all the input lines except the first one?

$ printf 'apple\nfig\ncarpet\njeep\nbus\n' | # ???
fig
carpet
jeep
bus

9) Which command(s) would you use to get the output shown below?

$ cat fruits.txt
banana
papaya
mango
$ cat blocks.txt
%=%=
apple
banana
%=%=
brown
green

# ???
banana
papaya
%=%=
apple

10) Use a combination of the head and tail commands to get the 11th to 14th characters from the given input.

$ printf 'apple\nfig\ncarpet\njeep\nbus\n' | # ???
carp

11) Extract the starting six bytes from the input files table.txt and fruits.txt.

# ???
brown banana

12) Extract the last six bytes from the input files fruits.txt and table.txt.

# ???
mango
 3.14