Some command line switches stand alone. Others are followed by options, such as a starting value, filename, and other settings. The getopt() function processes these values along with the switches, providing you know the secret.
Before revealing the secret (you can wait), know that a switch-case structure nested in a while loop is the best way to process multiple switches. The following listing shows how such a beast is assembled:
2021_07_17-Lesson-a.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char *argv[]) { int r; /* suppress getopt()'s error message */ opterr = 0; while( (r=getopt(argc,argv,"az")) != -1 ) { switch(r) { case 'a': puts("-a option is activated"); /* do A option stuff here */ break; case 'z': puts("-z option is activated"); /* do Z option stuff here */ break; case '?': printf("'%c' is an invalid argument\n",optopt); break; default: puts("Unknown argument"); } } return(0); }
The program accepts two arguments, -a
and -z
, as shown at Line 12. They can be specified in any order, as shown by these sample runs:
$ ./a.out -a -z
-a option is activated
-z option is activated
$ ./a.out -z -a
-z option is activated
-a option is activated
You can even bunch them up:
$ ./a.out -az
-a option is activated
-z option is activated
$ ./a.out -za
-z option is activated
-a option is activated
Things get tricky for the getopt() function when a switch requires an option. (This is the secret part.) For example:
$ ./a.out -a 177
Above, the -a
switch requires an option, say the number of people who fully understand double pointers in C. To notify the getopt() function of such an option, suffix a colon to the switch’s character in the option string:
getopt(argc,argv,"a:z")
Above, the -a
switch has an option but -z
does not. The option is available immediately after the getopt() function reads the -a
. It’s accessed as a string through the optarg
global variable. So, when the option is a numeric value, you must convert it from a string to the proper data type.
The following code processes an argument for the -a
switch, but not the -z
switch:
2021_07_17-Lesson-b.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char *argv[]) { int r; /* suppress getopt()'s error message */ opterr = 0; while( (r=getopt(argc,argv,"a:z")) != -1 ) { switch(r) { case 'a': /* -a has an argument */ printf("-a option with argument %s\n",optarg); /* do A option stuff here */ break; case 'z': puts("-z option is activated"); /* do Z option stuff here */ break; case '?': printf("'%c' is an invalid argument\n",optopt); break; default: puts("Unknown argument"); } } return(0); }
In the case statements for option -a
(starting at Line 16), the optarg
variable is used in the printf() statement to output whatever argument follows -a
. As with sample output shown previously, you can specify -a
and -z
in any order, but -a
must have an argument, otherwise the optarg
variable is misread. For example:
$ ./a.out -a -z
-a option with argument -z
It’s up to your code to determine whether the proper argument is set — or even available. Otherwise the switches are misinterpreted and their purpose is lost.
For multiple arguments with options, set a colon after each one in the getopt() function’s argument string. This operation can be tricky: You must test for each switch’s options. Otherwise a missing argument throws off the entire process.
In next week’s Lesson, I cover the getopt_long() function, which processes full-word switches prefixed by a double-dash.