Video Coming Soon...

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

29: cat

The previous command nl was a simple starter to get you into the mode of making something from a description. Now you're going to take what you did and use that to implement a new command cat.

The new thing to use is getopt which make it easy to get command line options.

The Challenge

The cat utility "concatenates" files. Really all it does is read in a bunch of files and output them. It's very similar to nl and even has the same line numbering features.

Your task is to take the code you created for nl and turn it into cat. You should copy it to cat.cpp or a new project, and then change it to become the cat utility.

You can also practice creating a whole project from nothing by starting over fresh and making a totally new project for cat.

Your version of cat should be able to handle the -n and -s options.

The Code

See my first version of catView Source file cat.cpp Only

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

void dump_file(std::istream& in, bool number, bool squeeze) {
  std::string line;
  int line_count = 0;

  while(in) {
    getline(in, line);
    line_count++;

    if(line == "" && squeeze) continue;

    if(number) {
      fmt::println("{}: {}", line_count, line);
    } else {
      fmt::println("{}", line);
    }
  }
}

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

  while((opt = getopt(argc, argv, "ns")) != -1) {
    switch(opt) {
      case 'n':
        number = true;
        break;
      case 's':
        squeeze = true;
        break;
      default:
        fmt::print("USAGE: cat -ns [file]");
        return 1;
    }
  }

  if(optind < argc) {
    // there's files to process
    for(int i = optind; i < argc; i++) {
      std::ifstream in_file{argv[i]};
      dump_file(in_file, number, squeeze);
    }
  } else {
    dump_file(std::cin, number, squeeze);
  }
}

The Discussion

As I mentioned in the introduction this does almost the exact same thing as nl, just with line numbering being optional. The main difference in this code is using getopt to get command line options from the user.

Further Study

Now that you can reliably process command line options with getopt you should be able to implement more features for cat. I suggest also going back to nl and using getopt there too.

You can also start looking at creating an automated test harness for your cat. A quick way to start is to create a test.sh or test.ps1 that just runs your cat in different ways to test it.

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.