Parsing Command Line Arguments in C++?
Solution 1
Boost.Program_options should do the trick
Solution 2
The suggestions for boost::program_options
and GNU getopt are good ones.
However, for simple command line options I tend to use std::find
For example, to read the name of a file after a -f
command line argument. You can also just detect if a single-word option has been passed in like -h
for help.
#include <algorithm>
char* getCmdOption(char ** begin, char ** end, const std::string & option)
{
char ** itr = std::find(begin, end, option);
if (itr != end && ++itr != end)
{
return *itr;
}
return 0;
}
bool cmdOptionExists(char** begin, char** end, const std::string& option)
{
return std::find(begin, end, option) != end;
}
int main(int argc, char * argv[])
{
if(cmdOptionExists(argv, argv+argc, "-h"))
{
// Do stuff
}
char * filename = getCmdOption(argv, argv + argc, "-f");
if (filename)
{
// Do interesting things
// ...
}
return 0;
}
On thing to look out for with this approach you must use std::strings as the value for std::find otherwise the equality check is performed on the pointer values.
I hope it is okay to edit this response instead adding a new one, as this is based on the original answer. I re-wrote the functions slightly and encapsulated them in a class, so here is the code. I thought it might be practical to use it that way as well:
class InputParser{
public:
InputParser (int &argc, char **argv){
for (int i=1; i < argc; ++i)
this->tokens.push_back(std::string(argv[i]));
}
/// @author iain
const std::string& getCmdOption(const std::string &option) const{
std::vector<std::string>::const_iterator itr;
itr = std::find(this->tokens.begin(), this->tokens.end(), option);
if (itr != this->tokens.end() && ++itr != this->tokens.end()){
return *itr;
}
static const std::string empty_string("");
return empty_string;
}
/// @author iain
bool cmdOptionExists(const std::string &option) const{
return std::find(this->tokens.begin(), this->tokens.end(), option)
!= this->tokens.end();
}
private:
std::vector <std::string> tokens;
};
int main(int argc, char **argv){
InputParser input(argc, argv);
if(input.cmdOptionExists("-h")){
// Do stuff
}
const std::string &filename = input.getCmdOption("-f");
if (!filename.empty()){
// Do interesting things ...
}
return 0;
}
Solution 3
I can suggest Templatized C++ Command Line Parser Library (some forks on GitHub are available), the API is very straightforward and (cited from the site):
the library is implemented entirely in header files making it easy to use and distribute with other software. It is licensed under the MIT License for worry free distribution.
This is an example from the manual, colored here for simplicity:
#include <string>
#include <iostream>
#include <algorithm>
#include <tclap/CmdLine.h>
int main(int argc, char** argv)
{
// Wrap everything in a try block. Do this every time,
// because exceptions will be thrown for problems.
try {
// Define the command line object, and insert a message
// that describes the program. The "Command description message"
// is printed last in the help text. The second argument is the
// delimiter (usually space) and the last one is the version number.
// The CmdLine object parses the argv array based on the Arg objects
// that it contains.
TCLAP::CmdLine cmd("Command description message", ' ', "0.9");
// Define a value argument and add it to the command line.
// A value arg defines a flag and a type of value that it expects,
// such as "-n Bishop".
TCLAP::ValueArg<std::string> nameArg("n","name","Name to print",true,"homer","string");
// Add the argument nameArg to the CmdLine object. The CmdLine object
// uses this Arg to parse the command line.
cmd.add( nameArg );
// Define a switch and add it to the command line.
// A switch arg is a boolean argument and only defines a flag that
// indicates true or false. In this example the SwitchArg adds itself
// to the CmdLine object as part of the constructor. This eliminates
// the need to call the cmd.add() method. All args have support in
// their constructors to add themselves directly to the CmdLine object.
// It doesn't matter which idiom you choose, they accomplish the same thing.
TCLAP::SwitchArg reverseSwitch("r","reverse","Print name backwards", cmd, false);
// Parse the argv array.
cmd.parse( argc, argv );
// Get the value parsed by each arg.
std::string name = nameArg.getValue();
bool reverseName = reverseSwitch.getValue();
// Do what you intend.
if ( reverseName )
{
std::reverse(name.begin(),name.end());
std::cout << "My name (spelled backwards) is: " << name << std::endl;
}
else
std::cout << "My name is: " << name << std::endl;
} catch (TCLAP::ArgException &e) // catch any exceptions
{ std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
}
Solution 4
Solution 5
You can use GNU GetOpt (LGPL) or one of the various C++ ports, such as getoptpp (GPL).
A simple example using GetOpt of what you want (prog [-ab] input) is the following:
// C Libraries:
#include <string>
#include <iostream>
#include <unistd.h>
// Namespaces:
using namespace std;
int main(int argc, char** argv) {
int opt;
string input = "";
bool flagA = false;
bool flagB = false;
// Retrieve the (non-option) argument:
if ( (argc <= 1) || (argv[argc-1] == NULL) || (argv[argc-1][0] == '-') ) { // there is NO input...
cerr << "No argument provided!" << endl;
//return 1;
}
else { // there is an input...
input = argv[argc-1];
}
// Debug:
cout << "input = " << input << endl;
// Shut GetOpt error messages down (return '?'):
opterr = 0;
// Retrieve the options:
while ( (opt = getopt(argc, argv, "ab")) != -1 ) { // for each option...
switch ( opt ) {
case 'a':
flagA = true;
break;
case 'b':
flagB = true;
break;
case '?': // unknown option...
cerr << "Unknown option: '" << char(optopt) << "'!" << endl;
break;
}
}
// Debug:
cout << "flagA = " << flagA << endl;
cout << "flagB = " << flagB << endl;
return 0;
}
Related videos on Youtube
Verhogen
Updated on February 11, 2021Comments
-
Verhogen over 3 years
What is the best way of parsing command-line arguments in C++ if the program is specified to be run like this:
prog [-abc] [input [output]]
Is there some way of doing this built into the standard library, or do I need to write my own code?
Related:
-
Mitch Wheat almost 14 yearsI think the Nunit source code (C#) has a good example of a command line handling class....
-
Andrejs Cainikovs almost 8 yearsThe easiest would be to use one of the argument parsing libraries:
getopt
orargparse
. -
stefaanv almost 8 yearsIf you can't use libraries (e.g. boost), at least use
std::vector<std::string> args(argv, argv+argc);
so you can parse a vector of strings instead of an array of char-arrays. -
Dharma over 6 yearsFor people using OpenCV already in their program, cv::CommandLineParser may also be a good choice. [ I mean just in case you are using it already for other purpose, I don't mean to include OpenCV for command line parser.]
-
juzzlin over 4 yearsRecently wrote this for modern c++: github.com/juzzlin/Argengine
-
droptop over 3 yearschechout github.com/p-ranav/argparse
-
-
robottobor over 15 yearsor getopt_long if you've got it
-
Aaron over 15 yearsI'm not sure if getopt is available on windows. I know it is in C on GNU
-
Johannes Schaub - litb over 15 yearsmy co-worker used it on windows. im quite sure it's available on windows
-
brofield about 15 yearsThis doesn't help to do anything that can't be already done with argc/argv.
-
Ankit Roy about 15 years@brofield: Sure, it doesn't change the world. But I find the == and value semantics simplify things enough that I keep using it.
-
hookenz almost 15 yearsGood choice. Alternatively, if you can't use boost for some reason then the standard c based "getopt" function will also get the job done.
-
Jonathan Graehl almost 15 yearsDoes it allow you to show the current and default values? A few years ago I had to implement a wrapper around it to show the effective options (based on parsed configs/args, and not just showing the strings supplied).
-
Jonathan Graehl almost 15 yearsLooks nice for simple use. I've always liked "options as global variables defined anywhere you please" for small tools. Primitives + string only which can be a big minus.
-
sorin about 14 yearsFYI, GNU getopt is GPL and getoptpp is also GPL so boost variant could be better for non open-source software.
-
Hamish Grubijan almost 14 years@j_random_hacker - what if I want to remember the order of the arguments? For instance, if the user typed
mycommand.exe -h file.csv
, I want to tell them that they are not using the utility correctly and why (should not supply a file name if they are just using the version). This example is rather simple, but I can think of more convoluted flags. The end result would be: sometimes the order does matter, and sometimes it does not. So ... how should I proceed then? Let me know if you have a question about my question. -
Ankit Roy almost 14 years@Hamish: I'm a bit confused -- loading the strings into a vector doesn't "lose" their order. You can still access the ith argument with
args[i]
(in fact I often do this myself, as the comment in my code snippet says). The iterator style is just a bit more convenient if you only need to deal with one at a time. Does that answer your question? -
Dirk Eddelbuettel almost 14 yearsNot really as the question was about C++ and Getopt is just plain C. There used to be a C++ variant of it but for some reason it was withdrawn.
-
pm100 almost 14 yearsit works fine in c++ tho; its what we use in all our c++ code.
-
Dirk Eddelbuettel almost 14 yearsWell yes but you can do much better with e.g. TCLAP. I add or remove one line with new option definition and I do not need to edit code in other place --> not so true with old school getopt.
-
Matthieu M. almost 14 years+1, didn't know about tclap and it manages to be lightweight and yet feels complete, I'm definitely going to delve deeper.
-
gatopeich about 13 yearsThe documentation for boost::program_options could be more complete. It is specially difficult to find out how to use files to keep the options, a critical feature.
-
gatopeich about 13 yearsThis seems the most obvious option for C++, but its documentation is not complete enough. Try to find there how to store and retrieve options from a file, an essential feature. I dislike how the code using it looks, specifically the wording
options.add_options()(option1)(option2)...
which I consider an abuse of C++ grammar. -
Otto Allmendinger over 12 years-1: this fetches array elements without bound checks
-
iain over 12 yearsI Rick you are correct about the #include thanks for updating my answer
-
Poul K. Sørensen over 12 yearsJust a question, do i need to do anything or does this work out of the box? You write to look out for : std::strings - so should i convert char* to a std::string anywhere or ?
-
iain over 12 yearsThis works out of the box. However note that the option parameter is
const std::string&
. It is important that the value parameter tostd::find
is astd::string
so thatstd::string::operator==()
is used not thechar * operator==()
(as the latter will only compare the pointer value and not the string contents). -
Sebastian Mach about 12 years-1: because of no bounds checking
-
Richard about 12 yearsCompiling code with Boost.Program_options did not seem straight-forward and required linking options, et cetera, beyond the inclusion of the header file.
-
Richard about 12 yearsThis option turned out to be the simplest for me, though it did add a sub-directory to my program with a number of header files. The include paths needed editing accordingly.
-
Matthew Flaschen about 12 years@SorinSbarnea, TINLA, but I believe the license is actually LGPLv2.
-
sorin about 12 yearsSorry but Google Code license on the project page states clearly GPL.
-
Matthew Flaschen about 12 years@SorinSbarnea, did you look at my link? I should have made it clearer, but I was referring to getopt and getopt-gnu, not getoptpp.
-
Keith Thompson about 12 years@RobertMunafo: The references to
argv[i+1]
can easily go outside the bounds of theargv
array. Think about running the program with"-i"
as the last argument. -
Marc Mutz - mmutz about 12 years@RobertMunafo: correct,
argv[argc]
is required to be0
. Assigning that tofilename
and passing it toprintf()
will crash at runtime, though. And even if we don't fall off the end, the code doesn't sufficiently advancei
after it parses an argument. It will try to parse the argument value as an option name next time around the loop. -
Robert Munafo about 12 years-1 for being a "roll-your-own" answer, whereas the question asks specifically for a "library in STL" that will do the task. Also, as noted by Keith Thompson and mmutz, there are some bugs in bounds checking.
-
Sean over 11 yearsI've used getopt, google's gflags, program_options from Boost and tclap is fantastic. I can't say enough good things about tclap, especially considering the available alternatives. The extent of the gripes that I have is that it's help formatting is "different" than what my eye is used to.
-
Luis Machuca over 11 yearsYou can get pretty much the same for much less. If you want things like
--long-option
, it's fairly straightforward to do yourself. -
Sean about 11 yearsStarting with version 0.1.3, the license is now MIT. I'm trying this out on a new project instead of TCLAP and so far it looks very promising. The file config option is quite nice.
-
Andrew Larsson over 10 yearsI just tried out exOptionParser, but it has so many problems. First of all, I get 58 warnings about unsigned int to int conversion. It also tries to increment list iterators (which can't be used like that) and crashes. Its interface is so terrible as well. It uses references all over the place instead of just returning the data you want. It looks like a C library even though it's built on top of the C++ STL.
-
Asherah over 10 yearsThis looks pretty neat. Glad I scrolled down; there's just nothing very good for plain C, save this!
-
Moshe Rubin over 10 yearsI've used all kinds of solutions over the years, including my own home-rolled one. I join the others in extolling the virtues of TCLAP. it was easy to integrate and answers my needs.
-
Stephen over 10 yearsintroducing boost to a code base just to parse command line options is a bit "sledgehammer to crack a nut". If boost is there already use it. Otherwise have a look at something like gopt. Nothing against boost in general but its kinda heavyweight and i find that the versions are tied tightly to g++ versions.
-
Joe about 10 yearsLooks like the project moved to sourceforge.
-
user18490 about 10 yearsI found the comments really harsh. I think it's fair to show also an example of how this can be done without using a library. This answer is complementary +1, sorry.
-
lmat - Reinstate Monica almost 10 yearsThis doesn't work as expected, for instance, like the tar application:
tar -xf file
, right? Each option must be separated.grep -ln pattern file
wouldn't be understood, but would have to begrep -l -n pattern file
. -
iain almost 10 yearsAbsolutely if you want posix style command line options then you should use one of the command line processing libraries mentioned in other answers. As this answer says this is for simple command line options.
-
Thomas Eding over 9 yearsGetopt is stupidly low level for a C++ program. I highly recommend AGAINST using it for a C++ program.
-
Thomas Eding over 9 yearsUghh. I understand the use of this library in C code, but IMO, this is way too low level to be acceptable in any C++ application I've ever written. Find a better library if you don't need pure C.
-
Samaursa over 9 yearsLink for future reference: sourceforge.net/projects/optionparser
-
SmallChess over 9 yearsFurthermore, boost::program_options is not a header only library. You'll have to build boost. This is very troublesome.
-
naufraghi almost 9 years@JohnShedletsky are you sure? I don't use the lib any more but in the manual are showed both long and short format arguments.
-
johnwbyrd almost 9 yearsTCLAP works, though its Windows roots are showing. It does compile clean on other platforms, but there are lots of Windowsy default choices: flags are separated from parameters by spaces, not equals signs; flags can require only a short (one-letter) and a long representation; multiple arguments per flag handling is wonky. On the plus side, it works on Mac too, it's not infected with GPL, it's quick to understand, it provides a convenient --help command, and it has no real external dependencies.
-
John Shedletsky almost 9 years@naugraghi Actually it does work but the error I was getting was misleading.
-
Max Lybbert over 8 years(Thank you @QPaysTaxes for noticing the link was broken; I don't know why your edit was rejected, but you were definitely correct).
-
AlwaysLearning over 8 yearsWhy does the distribution have a configuration script and a
Makefile
if the library is header-only? -
naufraghi over 8 years@AlwaysLearning Opening the
Makefile
it seems to be there to run the tests, compile the docs and build the examples. -
Tomáš Dvořák about 8 yearsThis is nice, but two minor improvements were needed: First, constructor params should be const-qualified, second, return value of getCmdOption should be a value, not a reference, otherwise you run into stackoverflow.com/questions/1339601/…. Other than that, a nice and simple solution, I'll use that, thanks.
-
AamodG about 8 yearsAn important note: This class does not compile as is with Visual Studio compiler (I'm using 2010 version). You must explicitly include <string> header to your program (iostream and vector are not sufficient). Got this solution from : stackoverflow.com/questions/9080028/…
-
MarcusJ almost 8 yearsSounds great, but it seems a bit too big. Also, I'm just looking for a way to parse out scanf format specifiers from an argument, I've already written my own (albeit more basic) parser.
-
jamesdlin almost 8 years@MarcusJ It seems a little weird that you say that this is too big (it's much smaller than most other command-line option parser) yet that you want it to parse printf/scanf format specifiers (which isn't something that command-line option parsers typically do)...
-
MarcusJ almost 8 yearsYeah, I know I've got some specific requirements for this, I'm just gonna go ahead and rewrite my option parser, but I did look at your code and the idea of passing in a struct to contain the various options is really interesting (so far mine is just hard coded). It's not too big on it's own, it's just that I've got a single .c/.h project, and your code would double the amount of code I've already got, so it's too big for my specific project.
-
Kemin Zhou over 7 yearsOn one extreme, for really simple programs or you just directly work with argv[] array. Another situation, for total flexibility in your arguments you can work with argv array directly (you can do prog -1 firstinput -2 second input -obj {constructor arguments ..}). Otherwise use boost, tclap, or many others.
-
lrineau over 7 years1. @iain What is the license of that piece of code? 2. @TomášDvořák is right about the return reference to a temporary, when
getCmdOption
returns the empty string.InputParser
should have astd::string empty_string
as a member, and return its reference when the option is not found. -
iain over 7 yearsThe first piece of code is mine the second was a edit by someone else. Regarding my code there is no licence it is public domain, feel free to use as you like without any warranty. I am not sure about the second. Regarding the InputParser class I am happy that it was contributed to my answer, but I would not put the args into a vector, but store
argv
andargv + argc
as thebegin
andend
iterators. -
Admin over 7 yearsboost seems like a total overkill for this task
-
Mike Weir about 7 yearsDidn't vote this one down, but I'm personally not a fan of something small like this having the dependency of exceptions.
-
Mike Weir about 7 yearsSimilar to "The Lean Mean C++ Option Parser", but has a much better API. Highly recommended.
-
edW about 7 yearsThere is also a GNU example of getopt with a value e.g. myexe -c myvalue You can try to search for "Example of Parsing Arguments with getopt"
-
Asalle about 7 yearsIt does not support any other OS but Windows
-
Asalle about 7 yearsIt returns false from functions, that is supposed to return char*, how is that possible? (the function is inline const char* GetPot::__match_starting_string(const char* StartString))
-
Asalle about 7 yearsIncredibly error-prone, in my opinion, e. g. I received a segfault after segfault (in the lib code) while using it
-
Jay about 7 years@Asalle What makes you say it's windows only?
-
kebs about 7 years@Asalle No idea, but this seems like an "inside" function, not part of the API. In case you have a doubt, better ask the author.
-
Beginner almost 7 years@Robert Munafo the asks for a way to parse the command line and additionally wether there is an STL-lib.
-
2-complex over 6 yearsIt uses strcpy_s. I had some luck getting it to work on macos by writing my own quick-and-dirty strcpy_s that calls strcpy.
-
Peter Mortensen almost 6 yearsWhat do you mean by "... is not too immediate to use"? Can you elaborate?
-
Vsevolod A. almost 6 years@iain I am getting an error:
no instance of function template "std::find" matches the argument list argument types are: (__gnu_cxx::__normal_iterator<const std::__cxx11::string *, std::vector<std::__cxx11::string, std::allocator<std::__cxx11::string>>>, __gnu_cxx::__normal_iterator<const std::__cxx11::string *, std::vector<std::__cxx11::string, std::allocator<std::__cxx11::string>>>, const std::__cxx11::string)
-
iain over 5 yearsI am not sure why. I haven't written any c++ in years. From the error you are getting it looks like you are using the code at the bottom added by someone else. Sorry I cannot be more help, but I do not even have a c++ compiler installed that I could test this out with.
-
kraxor over 5 yearsThis answer is crying out for a simple example IMHO.
-
Totte Karlsson over 5 yearsNote; detection of unknown arguments don't work. Also, the header gives compile errors if not placed before other headers. I'll look for another parser..
-
Stéphane almost 5 yearsWas initially reluctant, but noticed it was in the Ubuntu repo which made it extremely easy:
sudo apt-get install libtclap-dev
. Within a short amount of time had replaced my custom argv parsing with calls into TCLAP, including a few custom TCLAP::Constraint classes for validation. Works as advertised, will definitely use it again. Thanks for the link, would never otherwise have heard about it. -
András Aszódi over 4 years
boost::program_options
is hopelessly overengineered, difficult to use, and underdocumented. One of the few Boost libraries that would greatly benefit from a complete redesign and rewrite. Don't use it if you can avoid it. -
MarkWayne over 4 yearsI can't think of a less helpful reply to a question. 'It's solved. Pick one.' Sorry, but "duh." With my about um 15 minutes of thinking about this problem, I have come up with about 30 different scenarios about how one could approach it. I suspect the 'correct' response is more akin to explaining how a particular set of concerns would lead to a particular set of code implementations. But, hey, thanks for calling.
-
solstice333 about 4 years
-
finnmglas almost 4 yearshere's an example example provided by the GNU itself ^^
-
mh8020 over 3 yearsGood solution! - Why add a library for something that can be done in a few lines of rather simple code. Especially if your program doesn't use any other libraries, and considering that C++ doesn't have a standard package manager yet. With bounds checking, as suggested above: e.g.
if (strcmp(argv[i], "-i") == 0 && argv[i+1]) { filename = argv[++i]; ... }