Class 3: Command Line Switches


Reading
Continue with sections 1.1 though 1.5 of The Art of Unix Programming. It's only about 7 pages, and it's very readable.
Homework
  1. Add command-line options to your Project. See the version 0.2 milestone on the Project 1 page. Your project pages should be updated accordingly.

More Project 1
At this point, with everyone's Project 1 v0.1 up on their websites, which are linked off of the Project 1 page. We combined these programs in class to solve the following problem: Construct a histogram of sines of the squares of the first 10000 integers. This may sound a bit silly, but an interesting observation can actually be made out of all of this. Anyway, here's how the calculator "bc" and your projects can be combined to make this happen:
echo "for(i=1; i <= 1000; ++i) s(i*i)" | bc -l | scaler | GetYoFreqOn | ReturnZero | pp

First, echo "for(i=1; i <= 10000; ++i) s(i*i)" | bc -l generates the sines of the squares of the first 10000 numbers. Then scaler scales the results so that instead of falling in the range -1..1, as sine does, they are scaled to fall in the range 0..100. Then GetYoFreqOn counts the number of values falling in the bins [0,1),[1,2),...,[98,99),[99,100] and prints out those 100 frequency counts. Then ReturnZero adds adds on x-coordinates to the frequency values to provide evenly spaced points. Finally pp (or epsplot if you'd prefer a printable picture) plots the points in a nice window on the screen.

Important Lesson By saying less, by providing a less elaborate interface, by making minimalist I/O requirements, we end up with programs that can be tied together in new and interesting ways!

For example, now we have a nice function plotter. To plot sin(x^2) in the range -2..2, we could enter:

echo "for(x=-2; x <= 2; x=x+0.05) s(x*x)" | bc -l | scaler | ReturnZero | pp
Try it and see what happens.

Command line switches
Seeing the function plotting example from above, we might decide that it would be nice if the user could tell pp to connect the points it plots with lines. If pp asked the user whether he wanted this option, and the user had to type some response, the pipeline we set up would be messed up. Same thing for any of the other pieces of our pipeline, which the user might like to control similarly. Therefore, we are led inexorably to command-line options as the way to allow the user to modify the behaviour of programs --- like the -l in the call to wc -l. What we really want, then, is a -l option for pp to tell it to draw lines between the points.

Every program you launch from the command line is given an array of each of the strings that was typed onto the command line in launching that program (called the argument vector) and an integer telling you how many elements that array has. the name of the program is the first of these. Here is a demonstration of how that information can be accessed:

/* A silly program demonstrating command line arguments */
#include <iostream>
#include <string>
using namespace std;

int main(int argc, char **argv)
{
  for(int i = 0; i < argc; ++i)
  {
    cout << "argv[" << i << "] = " << argv[i] << endl;
  }

  return 0;
}

Here are several runs of the above program, demonstrating what kind of output you get.
valiant[1] [~/courses/SI486AS05/classes/L03/]> g++ -o ex1 ex1.cpp
valiant[140] [~/courses/SI486AS05/classes/L03/]> ./ex1
argv[0] = ./ex1
valiant[2] [~/courses/SI486AS05/classes/L03/]> ex1 "the end"
argv[0] = ex1
argv[1] = the end
valiant[3] [~/courses/SI486AS05/classes/L03/]> /home/wcbrown/courses/SI486AS05/classes/L03/ex1 -s 7
argv[0] = /home/wcbrown/courses/SI486AS05/classes/L03/ex1
argv[1] = -s
argv[2] = 7
It is important to note that the strings in argv are c-style strings, not C++ string objects. That means you need to use strcmp to compare strings, strlen to get their length, etc. It's easier to simply assigning the element of argv to a C++ string object, which then can be manipulated a bit more easily.


Christopher W Brown
Last modified: Wed Jan 12 17:13:18 EST 2005