Video Coming Soon...

Created by Zed A. Shaw Updated 2026-04-30 02:05:52

33: tail

The tail command is the inverse of the head command. It prints the last -n number of lines. It's also more difficult to implement efficiently. You'll make a version here that will be "good enough."

The Challenge

The challenge for this exercise is to once again use what you know from implementing head to create a totally new project from scratch that does tail. Read the documentation for tail to make sure you understand how it works, and at a minimum implement the -n option.

The Code

Here's my simple implementation of tail:

See my first version of tailView Source file tail.cpp Only

#include <fmt/core.h>
#include <iostream>
#include <unistd.h>
#include <fstream>
#include <vector>
#include <algorithm>

void collect_tail(std::istream& in, int count) {
  std::string line;
  std::vector<std::string> lines;

  while(in) {
    getline(in, line);
    lines.emplace_back(line);
  }

  int start = std::max(0, int(lines.size()) - count);

  for(size_t i = start; i < lines.size(); i++) {
    fmt::println("{}", lines[i]);
  }
}


int main(int argc, char* argv[]) {
  int opt = 0;
  int number = 10;

  while((opt = getopt(argc, argv, "n:")) != -1) {
    switch(opt) {
      case 'n':
        number = std::stoi(optarg);
        break;
      default:
        fmt::println("USAGE: tail -n <NUM> [file...]");
        return 1;
    }
  }

  if(optind < argc) {
    for(int i = optind; i < argc; i++) {
      std::ifstream in_file{argv[i]};
      collect_tail(in_file, number);
    }
  } else {
    collect_tail(std::cin, number);
  }
}

The Discussion

This version of tail is not efficient. It'll work fine for small files, but once the files become large you'll run into two problems:

  1. It'll take forever to get to the end of the file since this tail needs to read the whole file to find the end.
  2. It has to store the whole file into memory just to find the end.

For a simple beginner implementation this is fine, but it can be better.

Further Study

How can you make this more efficient? If you read the documentation for ifstream you'll see a function named tellg and another one names seekg. These functions allow you to skip ahead to different sections of a file.

Using this you could skip to the end of the file, and roll back a little to count the lines. Keep skipping back a bit and counting lines until you have enough, then print that.

This wouldn't work on std::cin but would work on files. Give it a try.

Previous Lesson Next Lesson

Register for Learn C++ the Hard Way

Register to gain access to additional videos which demonstrate each exercise. Videos are priced to cover the cost of hosting.