- Richard Feynman -
Command line parser
Contents
Why command line?
Think about starting a washing machine. The user (of the washing machine) needs to press buttons to chose:
- program (white 90, white 60, color 60, color 40)
- tumble dry
- eco mode (slower but more friendly to out environment)
We don't want the machine to ask us a question in the middle of the program, because we would then have to stand by the machine for the whole time. Instead we want to tell the machine what to do before starting and then leave the machine. The machine will then execute the program non-interactively. It is the same with command line arguments to a program. If we want to encode some files to ogg (an audio format) we don't want the program to interactively ask us if it should continue or not for each file. We want to tell the program what to do, on the command line, and then the program shall proceed without asking questions.
Why this page?
We (the authors of this book) have seen many so called odd solutions to parse command like arguments. Some of them have resulted in Spaghetti code. Some of the worst examples contain tons of if statements for just 2-3 command line arguments. Such a solution to a program with say 30 different command line options will result in horrific code.
We will show you the simple basics behind parsing command line arguments and also list some frameworks that we can use to parse. We aim at provide a solutions that:
- is easy to understand
- works in many languages - although the syntax may differ
- gives an understanding of what parser frameworks do
We also believe that the exercises will add to your experience and make you a better programmer.
What we expect from our program's command line options
We need to set a common ground before we continue the discussion on how to parse.
Our requirement on a program's command line options:
- the program accepts several different command line options
- the program shall not force any order of the command line options to the user
- some options may take optional parameters (i.e
--time 5
where--time
is the option and5
is the extra parameter
Example of bad parser
if (nrArgs==1) {
do_something()
} else if (nrArgs==2) {
do_something();
do_something_else(args[3]);
} else if (nrArgs==3) {
do_something();
do_something_else(args[3]);
do_something_different();
}
This solution is bad because it:
- does not check the actual options passed by the user, it silently assumes that if the user have passed an option it must be the correct one
- does not check the extra parameter
- it assumes that the options must come in a specific order
Why do you show us this bad example? We show you this code because we've seen similar too many times. Sometimes supervisors and sometimes even teachers write code like the above. Don't get tricked into writing such code.
How to think about the arguments
Think about the washing machine again. This time we (the users) shall pass our requests to a human, from now on called Mr Wash, using a piece of paper. Mr Wash in turn will use the machine. We write our choices down one by one on a new line. Mr Wash checks the lines one by one and pushes the buttons on the machine. The order of the instructions on our paper is irrelevant. If we want to instruct a program in a similar way, all choices are given to the program directly and no interaction afterwards, we use command line options.
Mr Wash has some features for us, we can now use these options:
- if you chose "mode" you must supply an extra argument with the color (i e "White" or "Color")
- if you chose "temperature" you must supply an extra argument with the temperature
A more formal way of writing this would be:
- mode <choice>
- temperature <temp>
- [eco mode]
The [ and ] reflects an option that is not required. The other two options are required.
This is all kind of good, but Mr Wash is not happy with this solutions so a new fancy feature is added for us. The program now assumes we want "Color 40" and "eco mode", so if no mode is chosen the program assumes we mean "Cllor 40". This is referred to as the default mode.
- if no options are given, Mr Wash assumes we want "Color 40" and "eco mode"
- if you chose "mode" you must supply an extra argument with the color (i e "White" or "Color")
- if you chose "temperature" you must supply an extra argument with the temperature
This makes the "mode" and "temperature" options optional/non required. A more formal way of writing this would be:
- [mode <choice>]
- [temperature <temp>]
- [eco mode]
Note here that all options are optional - you don't have to supply any. If you provide Mr Wash with a blank paper Mr Wash will use "Color 40" and "eco mode". Using a default mode like this is very common for programs.
Exercise
- Execute the program
ls
with no options/arguments. - Execute the program
ls
with the following argument/tmp
. - Execute the program
ls
with the following argument--help
. ls now lists its options. What options are optional and what options are required? - Execute the program
ls
with the following argument--does-not-exist
. before you actually do it, think about what happens?
Number of arguments given by the user
We don't know in advance (at compile time - when developing (writing and compiling) the code) how many arguments the user will supply but the system will tell us when the program is executed (at run time) how many arguments were supplied this specific execution. In the case of Mr Wash the number of options is the number of lines. It is not possible for Mr Wash to know in advance what options you will chose at a specific date and time, but Mr Wash will know how many lines you've written (i e the number of options) when you pass the piece of paper to him - it's only a matter of looking at the paper.
To check the number of arguments passed to our program is really easy:
Java example
When a Java program starts the command line options are put in an array for us. When writing a main method we must write it like this.
public static void main(String args[])
We could use a different name for the array, but most people call it args
so let's do the same. In this array we will find the arguments the user have supplied. To check the number of arguments we simply check the size of the array.
package org.progund.parse;
public class NrArgsExample {
public static void main(String args[]) {
System.out.println("You have supplied: " +
args.length + " argument(s)");
}
}
Let's compile and use our program:
$ javac org/progund/parse/NrArgsExample.java
$ java org.progund.parse.NrArgsExample
You have supplied: 0 argument(s)
$ java org.progund.parse.NrArgsExample one two three
You have supplied: 3 argument(s)
C example
When a C program starts the command line options are put in an array for us, just like in Java. When writing a main function we can write it like this:
int main()
In the main function above we discard all arguments. We can also write a main function like hits
int main(int argc, char **argv)
We could use a different name for the int and the array, but most people call them argc
and argv
so let's do the same. The value of argc is the number arguments the user have supplied.
Note: There is a third argument you can check in C. For us in this chapter this third arguments is irrelevant so we discard it
#include <stdio.h>
int main(int argc, char **argv) {
printf("You have supplied: %d argument(s)\n", argc);
}
Let's compile and run our program:
$ gcc nr_args_example.c -o nr_args_example
$ ./nr_args_example
You have supplied: 1 argument(s)
$ ./nr_args_example one two three
You have supplied: 4 argument(s)
Note: In C the program name itself is an argument so the number of arguments is one bigger than in Java
If we have a program that will behave a bit different if the user supplies "--long" on the command line we could write the program like this:
#include <stdio.h>
#include <string.h>
#define LONG_ARG "--long"
int main(int argc, char**argv)
{
int i;
int use_long = 0;
for (i=1;i<argc;i++)
{
printf("Checking arg[%d] '%s' ", i, argv[i]);
if (strncmp(argv[i], LONG_ARG, strlen(LONG_ARG))==0)
{
printf (" long found\n");
use_long=1;
}
else
{
printf (" syntax errror\n");
return 1;
}
}
printf ("All went well, we will");
if (use_long==0)
{
printf (" not");
}
printf (" use long listing\n");
return 0;
}
Note: it is not good programming practice to do everything in the main function. We did it to make the program as short as possible.
Loop through the arguments
Look at the arguments one by one. To do this we use a loop. We can use the fact that we know the number of arguments and then use the for loop
Exercises
- Write the code above using a while loop instead.
- Compare the solutions and list pros and cons.