head and tail

cat is useful to view entire contents of files. Pagers like less can be used if you are working with large files (man pages for example). Sometimes though, you just want a peek at the starting or ending lines of input files. Or, you know the line numbers for the information you are looking for. In such cases, you can use head or tail or a combination of both these commands to extract the content you want.

Leading and trailing lines

Consider this sample file, with line numbers prefixed for convenience.

$ 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

By default, head and tail will display the first and last 10 lines respectively.

$ head 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

$ tail sample.txt
 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

If there are less than 10 lines in the input, only those lines will be displayed.

# seq command will be discussed in detail later, generates 1 to 3 here
# same as: seq 3 | tail
$ seq 3 | head
1
2
3

You can use the -nN option to customize the number of lines (N) needed.

# first three lines
# space between -n and N is optional
$ head -n3 sample.txt
 1) Hello World
 2) 
 3) Hi there

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

Excluding the last N lines

By using head -n -N, you can get all the input lines except the ones you'll get when you use the tail -nN command.

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

Starting from the Nth line

By using tail -n +N, you can get all the input lines except the ones you'll get when you use the head -n(N-1) command.

# 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

Multiple input files

If you pass multiple input files to the head and tail commands, each file will be processed separately. By default, the output is nicely formatted with filename headers and empty line separators.

$ seq 2 | head -n1 greeting.txt -
==> greeting.txt <==
Hi there

==> standard input <==
1

You can use the -q option to avoid filename headers and empty line separators.

$ tail -q -n2 sample.txt nums.txt
14) He he he
15) Adios amigo
42
1000

Byte selection

The -c option works similar to the -n option, but with bytes instead of lines. In the below examples, the shell prompt at the end of the output aren't shown for illustration purposes.

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

# last three characters
$ printf 'apple pie' | tail -c3
pie

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

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

Since -c works byte wise, it may not be suitable for multibyte characters:

# all input characters in this example occupy two bytes each
$ printf 'αλεπού' | head -c2
α

# g̈ requires three bytes
$ printf 'cag̈e' | tail -c4
g̈e

Range of lines

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

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

# 6th to 7th lines
# same as: tail -n +6 sample.txt | head -n2
$ head -n7 sample.txt | tail -n +6
 6) Just do-it
 7) Believe it

info See unix.stackexchange: line X to line Y on a huge file for performance comparison with other commands like sed, awk, etc.

NUL separator

The -z option sets the NUL character as the line separator instead of the newline character.

$ printf 'car\0jeep\0bus\0' | head -z -n2 | cat -v
car^@jeep^@

$ printf 'car\0jeep\0bus\0' | tail -z -n2 | cat -v
jeep^@bus^@

Further Reading

Exercises

info The exercises directory has all the files used in this section.

1) 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=##### add your solution here
$ echo "$c"
car

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

$ printf 'apple\nfig\ncarpet\njeep\nbus\n' | ##### add your solution here
fig
carpet
jeep
bus

3) Which command would you use to get the output shown below?

$ cat fruits.txt
banana
papaya
mango
$ cat blocks.txt
----
apple--banana
mango---fig
----
3.14
-42
1000
----
sky blue
dark green
----
hi hello

##### add your solution here
==> fruits.txt <==
banana
papaya

==> blocks.txt <==
----
apple--banana

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

$ printf 'apple\nfig\ncarpet\njeep\nbus\n' | ##### add your solution here
carp

5) Extract the starting six bytes from the input files ip.txt and fruits.txt.

##### add your solution here
it is banana

6) Extract the last six bytes from the input files fruits.txt and ip.txt.

##### add your solution here
mango
erish

7) For the input file ip.txt, display except the last 5 lines.

##### add your solution here
it is a warm and cozy day
listen to what I say
go play in the park
come back before the sky turns dark

8) Display the third line from the given stdin data. Consider the NUL character as the line separator.

$ printf 'apple\0fig\0carpet\0jeep\0bus\0' | ##### add your solution here
carpet