how to parse command line arguments in C? - c

I am trying to parse command line arguments in C. Currently, I am using getopt do the parse. I have something like this:
#include <unistd.h>
int main(int argc, char ** argv)
{
while((c=getopt(argc, argv, "abf:")) != -1)
{
switch(c)
{
case 'a':
break;
case 'b':
break;
case 'f':
puts(optarg);
break;
case ':':
puts("oops");
break;
case '?'
puts("wrong command");
break;
}
}
}
then need to use ./a.out -fto run the program, and -f is the command element, but looks like -f must start with a '-', if I do not want the command element starts with '-', i.e, using ./a.out f instead of ./a.out -f, how to achieve it?
if getopt does not support parsing a command line in this way, are there any other library to use in C?

The argc and argv variables give you access to what you're looking for. argc is "argument count" and argv is "argument vector" (array of strings).
getopt is a very useful and powerful tool, but if you must not start with a dash, you can just access the argument array directly:
int main( int argc, char** argv) {
if( argc != 1) { /* problem! */ }
char * argument = argv[1]; // a.out f ... argv[1] will be "f"
}

You could use (on Linux with GNU libc) for parsing program arguments:
getopt with getopt_long; you might skip some arguments using tricks around optind
argp which is quite powerful
and of course you could parse program arguments manually, since they are given thru main(int argc, char**argv) on Linux (with the guarantee that argc>0, that argv[0] is "the program name" -e.g. to find it in your $PATH when it contains no / ..., that argv[argc] is the NULL pointer, and that before that every argv[i] with i<argc and i>0 is a zero-terminated string. See execve(2) for more.
GNU coding standards: command line interfaces document quite clearly some conventions. Please, obey at least the --help and --version conventions!
You might also be concerned by customizing the shell auto-completion facilities. GNU bash has programmable completion. zsh has a sophisticated completion system.
Remember that on Posix and Linux the globbing of command words is done by the shell before starting your program. See glob(7).

The getopt library will stop parsing at the first non-option argument. For command-based programs, this will be at the command name. You can then set optind to the index to start at and run getopt again with the command-specific arguments.
For example:
// general getopts
if (optind >= argc) return 0; // error -- no command
if (strcmp(argv[optind], "command") == 0)
{
++optind; // move over the command name
// 'command'-specific getopts
if (optind >= argc) return 0; // error -- no input
}
This should allow git-like command-line parsing.

Related

getopt usage with/without option

I'm writing a simple code making use of *argv[] parameter. I'd like to know whether I can use getopt() function for the following intent.
./myprogram -a PATH
./myprogram PATH
The program can either take merely PATH (e.g. /usr/tmp) or take -a option in addition to PATH. Can getopt() be used for this state? If can, how?
The program can either take merely PATH (e.g. /usr/tmp) or take option in addition to PATH. Can getopt() be used for this state? If can, how?
Certainly. I'm not sure where you even see a potential issue, unless its that you don't appreciate POSIX's and getopt()'s distinction between options and arguments. They are related, but not at all the same thing.
getopt() is fine with the case that no options are in fact specified, and it gives you access to the non-option arguments, such as PATH appears to be for you, regardless of how many options are specified. The usual usage model is to call getopt() in a loop until it returns -1 to indicate that no more options are available from the command line. At each step, the global variable optind variable provides the index of the next argv element to process, and after getopt() (first) returns -1, optind provides the index of the first non-option argument. In your case, that would be where you expect to find PATH.
int main(int argc, char *argv[]) {
const char options[] = "a";
_Bool have_a = 0;
char *the_path;
int opt;
do {
switch(opt = getopt(argc, argv, options)) {
case -1:
the_path = argv[optind];
// NOTE: the_path will now be null if no path was specified,
// and you can recognize the presence of additional,
// unexpected arguments by comparing optind to argc
break;
case 'a':
have_a = 1;
break;
case '?':
// handle invalid option ...
break;
default:
// should not happen ...
assert(0);
break;
}
} while (opt >= 0);
}
Using an optstring of "a" allows an argument of -a to act as a flag.
optind helps detect that only one additional argument is present.
The program can be executed as ./program -a path or ./program path
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
char op = ' ';//default value
int opt;
while ((opt = getopt(argc, argv, "a")) != -1)//optstring allows for -a argument
{
switch (opt)
{
case 'a':
op = 'a';//found option, set op
break;
default:
fprintf(stderr, "%s: unknown option %c\n", argv[0], optopt);
return 1;
}
}
if ( optind + 1 != argc)//one argument allowed besides optstring values
{
fprintf(stderr, "Usage: %s [-a] PATH\n", argv[0]);
return 1;
}
printf("%s %c\n", argv[optind], op);
return 0;
}

How to use command line options in a c command line tool?

I am trying to understand how to use command line options with a command line c tool and I came accross this example.Can some one explain how the code flow works,I am not able to understand it,also I understand that it uses a getopt() function which is inbuilt.
The exe called is rocket_to and it has two command line options, e and a. e option takes 4 as an argument and a option takes Brasalia,Tokyo,London as argument.
Can some one explain how the code works?
This is the actual code:
command line:
rocket_to -e 4 -a Brasalia Tokyo London
code:
#include<unistd.h>
..
while((ch=getopt(argc,argv,"ae:"))!=EOF)
switch(ch){
..
case 'e':
engine_count=optarg;
..
}
argc -=optind;
argv +=optind;
There are many manual pages for getopt() including the POSIX specification. They describe what the getopt() function does. You can also read the POSIX Utility Conventions which describes how arguments are handled by most programs (but there are plenty of exceptions to the rules, usually because of historical, pre-POSIX precedent).
In the example outline code, the -e option takes an argument, and that is the 4 in the example command line. You can tell because of the e: in the third argument to getopt() (the colon following the letter indicates that the option takes an argument). The -a option takes no argument; you can tell because it is not followed by a colon in the third argument to getopt(). The names Brasilia, Tokyo, London are non-option arguments after the option processing is complete. They're the values in argv[0] .. argv[argc-1] after the two compound assignments outside the loop.
The use of EOF is incorrect; getopt() returns -1 when there are no more options for it to process. You don't have to include <stdio.h> to be able to use getopt().
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int ch;
int aflag = 0;
char *engine_count = "0";
while ((ch = getopt(argc, argv, "ae:")) != -1)
{
switch (ch)
{
case 'a':
aflag = 1;
break;
case 'e':
engine_count = optarg;
break;
default:
fprintf(stderr, "Usage: %s [-a][-e engine] [name ...]\n", argv[0]);
exit(EXIT_FAILURE);
}
}
argc -= optind;
argv += optind;
printf("A flag = %d\n", aflag);
printf("Engine = %s\n", engine_count);
for (int i = 0; i < argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);
return 0;
}
That is working code which, if compiled to create a program rocket_to, produces:
$ ./rocket_to -e 4 -a Brasilia Tokyo London
A flag = 1
Engine = 4
argv[0] = Brasilia
argv[1] = Tokyo
argv[2] = London
$ ./rocket_to -a -e 4 Brasilia Tokyo London
A flag = 1
Engine = 4
argv[0] = Brasilia
argv[1] = Tokyo
argv[2] = London
$ ./rocket_to -e -a 4 Brasilia Tokyo London
A flag = 0
Engine = -a
argv[0] = 4
argv[1] = Brasilia
argv[2] = Tokyo
argv[3] = London
$
From the getopt man page:
The getopt() function parses the command-line arguments. Its arguments argc and argv are the argument count and array as passed to
the main() function on program invocation. An element of argv that starts with '-' (and is not exactly "-" or "--") is an option element. The characters of this element (aside from the initial '-') are option characters. If getopt() is called repeatedly, it
returns successively each of the option characters from each of the option elements.
The 3rd argument to getopt() are the valid options. If the option is followed by a colon it requires an argument. The argument can be accessed through the optarg variable. So in your example you have two options: 'a' which takes no argument and 'e' which takes an argument.
If getopt() finds an options it returns the character. If all options are parsed it returns -1 and if an unknown option is found it returns -1.
So your code loops through all options and processes them in a switch statement.
Next time when you have trouble understanding something like this try to run man <unknown function> first.

Handle segmentation fault accessing non-existent command line argument

I'm making a program in C in linux environment. Now, program runs with arguments which I supply in the command line.
For example:
./programName -a 45 -b 64
I wanted to handle the case when my command line parameters are wrongly supplied. Say, only 'a' and 'b' are valid parameters and character other than that is wrong. I handled this case. But suppose if my command line parameter is like this:
./programName -a 45 -b
It gives segmentation fault(core dumped). I know why it gives because there is no arguments after b. But how can I handle this situation such that when this condition arrives, I can print an error message on screen and exit my program.
As per the main function wiki page:
The parameters argc, argument count, and argv, argument vector, respectively
So you can use your argc parameter to check whether or not you have the right number of arguments. If you don't have 4, handle it and proceed without segfault.
You can, and quite probably should, use getopt() or its GNU brethren getopt_long().
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int b = 0;
int a = 0;
int opt;
while ((opt = getopt(argc, argv, "a:b:")) != -1)
{
switch (opt)
{
case 'a':
a = atoi(optarg);
break;
case 'b':
b = atoi(optarg);
break;
default:
fprintf(stderr, "Usage: %s -a num -b num\n", argv[0]);
exit(1);
}
}
if (a == 0 || b == 0)
{
fprintf(stderr, "%s: you did not provide non-zero values for both -a and -b options\n", argv[0]);
exit(1);
}
printf("a = %d, b = %d, sum = %d\n", a, b, a + b);
return(0);
}
You can make the error detection more clever as you wish, not allowing repeats, spotting extra arguments, allowing zeros through, etc. But the key point is that getopt() will outlaw your problematic invocation.
We can't see what went wrong with your code because you didn't show it, but if you go accessing a non-existent argument (like argv[4] when you run ./programName -a 42 -b), then you get core dumps. There are those who write out option parsing code by hand; such code is more vulnerable to such problems than code using getopt() or an equivalent option parsing function.

Proper getopt usage

Here there's an example on how to use GNU getopt. I understand most parts of the code but I have some questions:
Why is ctype lib included?
I mean unistd.h is needed for getopt, stdlib.h is needed for abort and stdio.h is the standard lib for io.
On the default case why do we use abort? cant' we just use return 1;?
I would like someone to share a link with more details on optopt, optind and optarg if possible.
ctype is needed for isprint()
not sure - it might be slightly useful if you're not doing this in the main function, but printing an error then calling exit(1) is probably better; I guess this is just a minimal example, and one line was shorter than two
Here are several links you might find useful:
FreeBSD man page for getopt(3)
Open Group UNIX Specification for getopt(3)
In brief:
optopt, optind, and optarg are external symbols. They're global, and are declared in unistd.h.
optopt (opt = option) isn't usually needed. It should be the same as the value returned by calling getopt.
optarg (arg = argument) is easy. It's for the argument to a flag. e.g. if -f is an option that requires a filename argument (optstring contains f:), you can do something like
case 'f':
filename = optarg;
break;
optind (ind means index) tells you where option process finished after the end of your while (flag = getopt...) block.
e.g. before you add option handling, your script might look like this
// print command line arguments, start at 1 to skip the program name
for (int i = 1; i < argc; i++) {
printf("arg[%d]=%s\n", i, argv[i]);
}
after adding your getopt block to handle options, you can do
// print command line arguments remaining after option processing
for (int i = optind; i < argc; i++) {
printf("arg[%d]=%s\n", i, argv[i]);
}
or
// skip command line options
argc -= optind; argv += optind;
// print command line arguments
for (int i = 0; i < argc; i++) {
printf("arg[%d]=%s\n", i, argv[i]);
}
If you don't have any required command line arguments, then you don't have to worry about optind.

Getopt - filename as argument

Let's say I made a C program that is called like this:
./something -d dopt filename
So -d is a command, dopt is an optional argument to -d and filename is an argument to ./something, because I can also call ./something filename.
What is the getopt form to represent get the filename?
Use optstring "d:"
Capture -d dopt with optarg in the usual way. Then look at optind (compare it with argc), which tells you whether there are any non-option arguments left. If so, your filename is the first of these.
getopt doesn't specifically tell you what the non-option arguments are or check the number. It just tells you where they start (having first moved them to the end of the argument array, if you're in GNU's non-strict-POSIX mode)
Check-out how grep does it. At the end of main() you'll find:
if (optind < argc)
{
do
{
char *file = argv[optind];
// do something with file
}
while ( ++optind < argc);
}
The optind is the number of command-line options found by getopt. So this conditional/loop construct can handle all of the files listed by the user.

Resources