SkillAgentSearch skills...

Structopt

Parse command line arguments by defining a struct

Install / Use

/learn @p-ranav/Structopt

README

<p align="center"> <img height="70" src="img/logo.png"/> </p> <p align="center"> Parse command line arguments by defining a struct </p> <p align="center"> <a href="https://github.com/p-ranav/structopt/releases"> <img src="https://img.shields.io/github/release/p-ranav/structopt.svg" alt="ci status"/> </a> <a href="https://conan.io/center/structopt/0.1.2"> <img src="https://img.shields.io/badge/Conan-package-blueviolet" alt="conan package"/> </a> <a href="https://travis-ci.com/p-ranav/structopt"> <img src="https://travis-ci.com/p-ranav/structopt.svg?branch=master" alt="ci status"/> </a> <a href="https://ci.appveyor.com/project/p-ranav/structopt/branch/master"> <img src="https://ci.appveyor.com/api/projects/status/fyufe5f11mhahwq9/branch/master?svg=true" alt="ci status"/> </a> <a href="https://www.codacy.com/manual/p-ranav/structopt?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=p-ranav/structopt&amp;utm_campaign=Badge_Grade"> <img src="https://app.codacy.com/project/badge/Grade/e6e76a680e61445a90616d27cb69b927" alt="codacy"/> </a> <a href="https://en.wikipedia.org/wiki/C%2B%2B17"> <img src="https://img.shields.io/badge/C%2B%2B-17-blue.svg" alt="standard"/> </a> <a href="https://github.com/p-ranav/tabulate/blob/master/LICENSE"> <img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="license"/> </a> </p>

Quick Start

#include <structopt/app.hpp>

struct Options {
   // positional argument
   //   e.g., ./main <file>
   std::string config_file;

   // optional argument
   //   e.g., -b "192.168.5.3"
   //   e.g., --bind_address "192.168.5.3"
   //
   // options can be delimited with `=` or `:`
   // note: single dash (`-`) is enough for short & long option
   //   e.g., -bind_address=localhost
   //   e.g., -b:192.168.5.3
   //
   // the long option can also be provided in kebab case:
   //   e.g., --bind-address 192.168.5.3
   std::optional<std::string> bind_address;
 
   // flag argument
   // Use `std::optional<bool>` and provide a default value. 
   //   e.g., -v
   //   e.g., --verbose
   //   e.g., -verbose
   std::optional<bool> verbose = false;

   // directly define and use enum classes to limit user choice
   //   e.g., --log-level debug
   //   e.g., -l error
   enum class LogLevel { debug, info, warn, error, critical };
   std::optional<LogLevel> log_level = LogLevel::info;

   // pair argument
   // e.g., -u <first> <second>
   // e.g., --user <first> <second>
   std::optional<std::pair<std::string, std::string>> user;

   // use containers like std::vector
   // to collect "remaining arguments" into a list
   std::vector<std::string> files;
};
STRUCTOPT(Options, config_file, bind_address, verbose, log_level, user, files);

Create a structopt::app and parse the command line arguments into the Options struct:

int main(int argc, char *argv[]) {

  try {
  
    // Line of code that does all the work:
    auto options = structopt::app("my_app").parse<Options>(argc, argv);

    // Print out parsed arguments:

    // std::cout << "config_file  = " << options.config_file << "\n";
    // std::cout << "bind_address = " << options.bind_address.value_or("not provided") << "\n";
    // std::cout << "verbose      = " << std::boolalpha << options.verbose.value() << "\n";
    // ...

  } catch (structopt::exception& e) {
    std::cout << e.what() << "\n";
    std::cout << e.help();
  }
}

Now let's pass some arguments to this program:

foo@bar:~$ ./main config.csv file5.csv file6.json
config_file  = config.csv
bind_address = not provided
verbose      = false
log_level    = 1
user         = not provided
files        = { file5.csv file6.json }

foo@bar:~$ ./main config.csv --bind-address localhost:9000 -v -log-level error file1.txt file2.txt
config_file  = config.csv
bind_address = localhost:9000
verbose      = true
log_level    = 3
user         = not provided
files        = { file1.txt file2.txt }

foo@bar:~$ ./main config_2.csv --bind-address 192.168.7.3 -log-level debug file1.txt file3.txt file4.txt --user "John Doe" "john.doe@foo.com"
config_file  = config_2.csv
bind_address = 192.168.7.3
verbose      = false
log_level    = 0
user         = John Doe<john.doe@foo.com>
files        = { file1.txt file3.txt file4.txt }

Table of Contents

Getting Started

structopt is a header-only library. Just add include/ to your include_directories and you should be good to go. A single header file version is also available in single_include/.

Positional Arguments

Here's an example of two positional arguments: input_file and output_file. input_file is expected to be the first argument and output_file is expected to be the second argument

#include <structopt/app.hpp>

struct FileOptions {
  // Positional arguments
  // ./main <input_file> <output_file>
  std::string input_file;
  std::string output_file;
};
STRUCTOPT(FileOptions, input_file, output_file);



int main(int argc, char *argv[]) {

  try {
    auto options = structopt::app("my_app").parse<FileOptions>(argc, argv);

    // Print parsed arguments:
    std::cout << "\nInput file  : " << options.input_file << "\n";
    std::cout << "Output file : " << options.output_file << "\n";

  } catch (structopt::exception& e) {
    std::cout << e.what() << "\n";
    std::cout << e.help();
  }
}
foo@bar:~$ ./main foo.txt bar.csv

Input file  : foo.txt
Output file : bar.csv

foo@bar:~$ ./main foo.csv
Error: expected value for positional argument `output_file`.

USAGE: ./my_app input_file output_file

ARGS:
    input_file
    output_file

Optional Arguments

Now, let's look at optional arguments. To configure an optional argument, use std::optional in the options struct like below.

#include <structopt/app.hpp>

struct GccOptions {
  // language standard
  // e.g., -std=c++17
  // e.g., --std c++20
  std::optional<std::string> std = "c++11";

  // verbosity enabled with `-v` or `--verbose`
  // or `-verbose`
  std::optional<bool> verbose = false;

  // enable all warnings with `-Wall`
  std::optional<bool> Wall = false;

  // produce only the compiled code
  // e.g., gcc -C main.c
  std::optional<bool> Compile = false;

  // produce output with `-o <exec_name>`
  std::optional<std::string> output = "a.out";

  std::string input_file;
};
STRUCTOPT(GccOptions, std, verbose, Wall, Compile, output, input_file);


int main(int argc, char *argv[]) {
  try {
    auto options = structopt::app("gcc").parse<GccOptions>(argc, argv);

    // Print parsed arguments

    std::cout << "std        : " << options.std.value() << "\n";
    std::cout << "verbose    : " << std::boolalpha << options.verbose.value() << "\n";
    std::cout << "Wall       : " << std::boolalpha << options.Wall.value() << "\n";
    std::cout << "Compile    : " << std::boolalpha << options.Compile.value() << "\n";
    std::cout << "Output     : " << options.output.value() << "\n";
    std::cout << "Input file : " << options.input_file << "\n";
  } catch (structopt::exception &e) {
    std::cout << e.what() << "\n";
    std::cout << e.help();
  }
}

NOTE structopt supports two option delimiters, = and : for optional arguments. This is meaningful and commonly used in single-valued optional arguments, e.g., --std=c++17.

foo@bar:~$ ./main -C main.cpp
std        : c++11
verbose    : false
Wall       : false
Compile    : true
Output     : a.out
Input file : main.cpp

foo@bar:~$ ./main -std=c++17 -o main main.cpp
std        : c++17
verbose    : false
Wall       : false
Compile    : false
Output     : main
Input file : main.cpp

foo@bar:~$ ./main main.cpp -v -std:c++14 --output:main -Wall
std        : c++14
verbose    : true
Wall       : true
Compile    : false
Output     : main
Input file : main.cpp

NOTE In summary, for a field in your struct named bind_address, the following are all legal ways to provide a value:

  • Short form:
    • -b <value>
  • Long form:
    • --bind_address <value>
    • -bind_address <value>
  • Kebab case:
    • --bind-address <value>
    • -bind-address <value>
  • Equal ('=') option delimiter
    • -b=<value>
    • --bind_address=<value>
    • -bind_address=<value>
    • --bind-address=<value>
    • -bind-address=<value>
  • Colon ':' option delimiter
    • -b:<value>
    • --bind_address:<value>
    • -bind_address:<value>
    • --bind-address:<value>
    • -bind-address:<value>

Double dash (--) Argument

A double dash (--) is used in most bash built-in commands and many other commands to signify the end of command options, after which only positional parameters are accepted.

Example use: lets say you want to grep a file for the string -v - normally -v will be considered the option to

Related Skills

View on GitHub
GitHub Stars507
CategoryDevelopment
Updated4d ago
Forks27

Languages

C++

Security Score

100/100

Audited on Mar 30, 2026

No findings