head and tail

cat is useful to view entire contents of file(s). 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 4 here
# same as: seq 4 | tail
$ seq 4 | head
1
2
3
4

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 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, newline characters have been added to the output for illustration purposes.

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

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

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

# all characters starting from 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̈ occupies three bytes
$ printf 'cag̈e' | tail -c4
g̈e 

Range of lines

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

# 9th to 11th lines
# same as: head -n11 sample.txt | tail -n3
$ 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 -n2
 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