Parsowanie argumentów linii poleceń w C++? [zamknięte]

Zamknięte . To pytanie musi być bardziej skoncentrowane . Obecnie nie przyjmuje odpowiedzi. Zamknięte 2 dni temu . zamknięty . To pytanie i jego odpowiedzi są zamknięte , ponieważ pytanie jest off-topic, ale ma znaczenie historyczne. Obecnie nie przyjmuje nowych odpowiedzi ani interakcji.

Jaki jest najlepszy sposób parsowania argumentów wiersza poleceń w C++, jeśli program ma być uruchamiany w następujący sposób:

prog [-abc] [input [output]]

Czy Jest jakiś sposób na zrobienie tego wbudowanego w standardową bibliotekę, czy chcesz napisać własny kod?


Powiązane:

Author: Cody Gray, 2009-05-14

30 answers

Boost.Program_options should do the trick

 89
Author: ChrisN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-21 21:22:25

Propozycje boost::program_options i GNU getopt są dobre.

Jednak dla prostych opcji wiersza poleceń używam std:: find

Na przykład, aby odczytać nazwę pliku po argumencie linii poleceń -f. Możesz również po prostu wykryć, czy opcja jednego słowa została przekazana w like -h w celu uzyskania pomocy.

#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;
}

Na rzecz, na którą należy zwrócić uwagę w tym podejściu, należy użyć STD:: strings jako wartości dla std:: find, w przeciwnym razie sprawdzanie równości jest wykonywane na wartościach wskaźnika.


Mam nadzieję, że można edytować tę odpowiedź zamiast dodawać nową, ponieważ jest ona oparta na oryginalnej odpowiedzi. Przerobiłem nieco funkcje i zamknąłem je w klasie, więc oto kod. Pomyślałem, że może być praktyczne, aby używać go w ten sposób, jak również:

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;
}
 271
Author: iain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-16 13:17:02

Mogę zasugerować Templatowaną bibliotekę parsera wiersza poleceń C++ (dostępne są niektóre widelce na Githubie), API jest bardzo proste i (cytowane ze strony):

Biblioteka jest zaimplementowana w całości w plikach nagłówkowych, co ułatwia używać i rozpowszechniać z innym oprogramowaniem. Jest licencjonowany na podstawie MIT Licencja na bezproblemową dystrybucję.

Jest to przykład z podręcznika, kolorowany tutaj dla uproszczenia:

#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; }
}
 63
Author: naufraghi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-28 15:14:13
 45
Author: Igor Semenov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-31 14:02:56

Możesz użyć GNU GetOpt (LGPL) lub jednego z różnych portów C++, np. getoptpp (GPL).

Prosty przykład użycia GetOpt of what you want (Prog [-ab] input) jest następujący:

// 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;
}
 37
Author: Matthew Flaschen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-06 19:04:50

GNU GetOpt .

Prosty przykład użycia GetOpt:

// C/C++ Libraries:
#include <string>
#include <iostream>
#include <unistd.h>

// Namespaces:
using namespace std;

int main(int argc, char** argv) {
    int opt;
    bool flagA = false;
    bool flagB = false;

    // 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;
}

Możesz również użyć optarg Jeśli masz opcje akceptujące argumenty.

 27
Author: Marcin Gil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-06 19:07:41

Jeszcze inną alternatywą jest Parser opcji Lean Mean C++:

Http://optionparser.sourceforge.net

Jest to biblioteka tylko nagłówkowa (w rzeczywistości tylko jeden plik nagłówkowy) i w przeciwieństwie do wszystkich innych sugestii jest również wolnostojący, tzn. nie ma żadnych zależności. W szczególności nie ma zależności od STL. Nie używa nawet WYJĄTKÓW ani niczego innego, co wymaga wsparcia biblioteki. Oznacza to, że może być połączony ze zwykłym C lub innym języków bez wprowadzania" obcych " bibliotek.

Jak boost:: program_options jego API oferuje wygodny bezpośredni dostęp do opcji, czyli możesz napisać kod w ten sposób

If (options [HELP])... ;

I

Int verbosity = options [VERBOSE].count ();

W przeciwieństwie do boost:: program_options jest to jednak po prostu użycie tablicy indeksowanej (dostarczonej przez użytkownika) enum. Oferuje to wygodę asocjacyjnego kontenera bez waga.

Jest dobrze udokumentowany i posiada przyjazną dla firmy licencję (MIT).

TLMC++op zawiera ładny formatter dla wiadomości użytkowania, które mogą zrobić zawijanie linii i wyrównywanie kolumn, co jest przydatne podczas lokalizacji programu, ponieważ zapewnia, że wyjście będzie dobrze wyglądać nawet w językach, które mają dłuższe wiadomości. Oszczędza to również uciążliwość ręcznego formatowania użycia dla kolumn 80.

 23
Author: MSB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-24 18:12:37
for (int i = 1; i < argc; i++) {

    if (strcmp(argv[i],"-i")==0) {
        filename = argv[i+1];
        printf("filename: %s",filename);
    } else if (strcmp(argv[i],"-c")==0) {
        convergence = atoi(argv[i + 1]);
        printf("\nconvergence: %d",convergence);
    } else if (strcmp(argv[i],"-a")==0) {
        accuracy = atoi(argv[i + 1]);
        printf("\naccuracy:%d",accuracy);
    } else if (strcmp(argv[i],"-t")==0) {
        targetBitRate = atof(argv[i + 1]);
        printf("\ntargetBitRate:%f",targetBitRate);
    } else if (strcmp(argv[i],"-f")==0) {
        frameRate = atoi(argv[i + 1]);
        printf("\nframeRate:%d",frameRate);
    }

}
 21
Author: Oliver Nina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-02 22:35:01

Uważam, że łatwiej jest używać ezOptionParser . Jest to również pojedynczy plik nagłówkowy, nie zależy od niczego poza STL, Działa Dla Windows i Linux (najprawdopodobniej również inne platformy), nie ma krzywej uczenia się dzięki przykładom, ma funkcje, których inne biblioteki nie mają (jak import/eksport plików z komentarzami, dowolne nazwy opcji z ogranicznikami, automatyczne formatowanie użycia itp.), i jest licencjonowany przez LGPL.

 19
Author: Remik Ziemlinski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-11 23:10:40

TCLAP to naprawdę ładna lekka konstrukcja i łatwa w użyciu: http://tclap.sourceforge.net/

 19
Author: cheshirekow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-21 06:31:30

Prawdopodobnie chcesz użyć do tego zewnętrznej biblioteki. Istnieje Wiele do wyboru.

Boost ma bardzo bogatą (jak zwykle) bibliotekę opcji programu Boost.

Moim ulubionym przez ostatnie kilka lat jest TCLAP -- czysto template, stąd brak biblioteki lub linkowania, automatyczne generowanie '--help' i inne gadżety. Zobacz najprostszy przykład z dokumentów.

 18
Author: Dirk Eddelbuettel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-30 00:35:34

Jeśli chcesz samodzielnie przetworzyć opcje linii poleceń, najprostszym sposobem jest postawienie:

vector<string> args(argv + 1, argv + argc);

Na górze twojego main(). Kopiuje wszystkie argumenty linii poleceń do wektora std::string s. Następnie można użyć == do łatwego porównywania łańcuchów, zamiast nieskończonych wywołań strcmp(). Na przykład:

int main(int argc, char **argv) {
    vector<string> args(argv + 1, argv + argc);
    string infname, outfname;

    // Loop over command-line args
    // (Actually I usually use an ordinary integer loop variable and compare
    // args[i] instead of *i -- don't tell anyone! ;)
    for (auto i = args.begin(); i != args.end(); ++i) {
        if (*i == "-h" || *i == "--help") {
            cout << "Syntax: foomatic -i <infile> -o <outfile>" << endl;
            return 0;
        } else if (*i == "-i") {
            infname = *++i;
        } else if (*i == "-o") {
            outfname = *++i;
        }
    }
}

[EDIT: zdałem sobie sprawę, że kopiuję argv[0], nazwę programu, do args -- fixed.]

 18
Author: j_random_hacker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-27 18:29:29

I jest dostępna Biblioteka Google.

Naprawdę, parsowanie wiersza poleceń jest " rozwiązane."Wybierz jedną.

 16
Author: Max Lybbert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-14 16:27:14

W C++ odpowiedź jest zwykle w Boost...

Boost.Opcje Programu

 15
Author: Ferruccio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-14 01:17:28

Spróbuj Boost:: Opcje Programu. Pozwala na odczyt i analizę linii poleceń, a także plików konfiguracyjnych.

 11
Author: thekidder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-17 03:18:46

Myślę, że GNU GetOpt nie jest zbyt natychmiastowy do użycia.

Qt i Boost mogą być rozwiązaniem, ale musisz pobrać i skompilować dużo kodu.

Zaimplementowałem więc parser, który tworzy std:: map<:> parametrów.

Na przykład wywołanie:

 ./myProgram -v -p 1234

Mapa będzie:

 ["-v"][""]
 ["-p"]["1234"]

Użycie to:

int main(int argc, char *argv[]) {
    MainOptions mo(argc, argv);
    MainOptions::Option* opt = mo.getParamFromKey("-p");
    const string type = opt ? (*opt).second : "";
    cout << type << endl; /* Prints 1234 */
    /* Your check code */
}

MainOptions.h

#ifndef MAINOPTIONS_H_
#define MAINOPTIONS_H_

#include <map>
#include <string>

class MainOptions {
public:
    typedef std::pair<std::string, std::string> Option;
    MainOptions(int argc, char *argv[]);
    virtual ~MainOptions();
    std::string getAppName() const;
    bool hasKey(const std::string&) const;
    Option* getParamFromKey(const std::string&) const;
    void printOptions() const;
private:
    typedef std::map<std::string, std::string> Options;
    void parse();
    const char* const *begin() const;
    const char* const *end() const;
    const char* const *last() const;
    Options options_;
    int argc_;
    char** argv_;
    std::string appName_;
};

MainOptions.cpp

#include "MainOptions.h"

#include <iostream>

using namespace std;

MainOptions::MainOptions(int argc, char* argv[]) :
        argc_(argc),
        argv_(argv) {
    appName_ = argv_[0];
    this->parse();
}

MainOptions::~MainOptions() {
}

std::string MainOptions::getAppName() const {
    return appName_;
}

void MainOptions::parse() {
    typedef pair<string, string> Option;
    Option* option = new pair<string, string>();
    for (const char* const * i = this->begin() + 1; i != this->end(); i++) {
        const string p = *i;
        if (option->first == "" && p[0] == '-') {
            option->first = p;
            if (i == this->last()) {
                options_.insert(Option(option->first, option->second));
            }
            continue;
        } else if (option->first != "" && p[0] == '-') {
            option->second = "null"; /* or leave empty? */
            options_.insert(Option(option->first, option->second));
            option->first = p;
            option->second = "";
            if (i == this->last()) {
                options_.insert(Option(option->first, option->second));
            }
            continue;
        } else if (option->first != "") {
            option->second = p;
            options_.insert(Option(option->first, option->second));
            option->first = "";
            option->second = "";
            continue;
        }
    }
}

void MainOptions::printOptions() const {
    std::map<std::string, std::string>::const_iterator m = options_.begin();
    int i = 0;
    if (options_.empty()) {
        cout << "No parameters\n";
    }
    for (; m != options_.end(); m++, ++i) {
        cout << "Parameter [" << i << "] [" << (*m).first << " " << (*m).second
                << "]\n";
    }
}

const char* const *MainOptions::begin() const {
    return argv_;
}

const char* const *MainOptions::end() const {
    return argv_ + argc_;
}

const char* const *MainOptions::last() const {
    return argv_ + argc_ - 1;
}

bool MainOptions::hasKey(const std::string& key) const {
    return options_.find(key) != options_.end();
}

MainOptions::Option* MainOptions::getParamFromKey(
        const std::string& key) const {
    const Options::const_iterator i = options_.find(key);
    MainOptions::Option* o = 0;
    if (i != options_.end()) {
        o = new MainOptions::Option((*i).first, (*i).second);
    }
    return o;
}
 10
Author: Luca Davanzo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-16 15:58:04

Istnieją Te narzędzia w bibliotece GNU C, która zawiera GetOpt .

Jeśli używasz Qt i lubisz interfejs GetOpt, froglogic opublikował ładny interfejstutaj .

 8
Author: Dusty Campbell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-31 14:19:07

Tooting my own horn jeśli Mogę, chciałbym również zasugerować rzucenie okiem na opcję parsing library, którą napisałem: dropt .

  • jest to biblioteka C (w razie potrzeby z opakowaniem C++).
  • Jest lekki.
  • jest rozszerzalny(niestandardowe typy argumentów mogą być łatwo dodawane i mają równe podstawy z wbudowanymi typami argumentów).
  • powinien być bardzo przenośny (jest napisany w standardzie C) bez zależności (innych niż standard C biblioteka).
  • posiada bardzo nieograniczoną licencję (Zlib / libpng).

Jedną z cech, które oferuje, a których wiele innych nie ma, jest możliwość nadpisania wcześniejszych opcji. Na przykład, jeśli masz alias powłoki:

alias bar="foo --flag1 --flag2 --flag3"

I chcesz używać bar ale z wyłączonym --flag1, pozwala to na:

bar --flag1=0
 7
Author: jamesdlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-04 03:42:48

Lubię getopt C (), ale wtedy jestem stary. :-)

 6
Author: John Deters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-17 03:19:02

Google ' s gflags

 6
Author: Craig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-17 03:20:12

Proponuję skorzystać z biblioteki. Jest klasyczny i czcigodny getopt{[2] } i jestem pewien, że inni.

 5
Author: Aaron Maenpaa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-14 01:18:22

Istnieje wiele dobrych bibliotek dostępnych.

Boost Program Options jest dość ciężkim rozwiązaniem, zarówno dlatego, że dodanie go do projektu wymaga zbudowania Boosta, a składnia jest nieco myląca (moim zdaniem). Jednak może zrobić prawie wszystko, w tym o opcje wiersza poleceń zastąpić te ustawione w plikach konfiguracyjnych.

SimpleOpt jest dość wszechstronnym, ale prostym procesorem wiersza poleceń. Jest to pojedynczy plik i ma prostą strukturę, ale obsługuje tylko parsowanie wiersza poleceń do opcji, musisz wykonać wszystkie sprawdzanie typu i zakresu. Jest dobry zarówno dla Windows, jak i Unix i jest dostarczany z wersją glob dla Windows.

Getopt jest dostępny w systemie Windows. Jest taka sama jak na maszynach Unix, ale często jest biblioteką GPL.

 5
Author: brofield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-21 08:45:02

AnyOption jest klasą C++ do łatwego parsowania złożonych opcji wiersza poleceń. Przetwarza również opcje z pliku rsourcefile w formacie pary wartości opcji.

AnyOption implementuje tradycyjne opcje znaków w stylu POSIX (- n), jak również nowsze opcje długie w stylu GNU (--name ). Możesz też użyć prostszej długiej opcji version (- name), prosząc o zignorowanie opcji stylu POSIX.

 5
Author: Jay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-17 15:23:19

Qt 5.2 zawiera API parsera linii poleceń.

Mały przykład:

#include <QCoreApplication>
#include <QCommandLineParser>
#include <QDebug>

int main(int argc, char **argv)
{
  QCoreApplication app(argc, argv);
  app.setApplicationName("ToolX");
  app.setApplicationVersion("1.2");

  QCommandLineParser parser;
  parser.setApplicationDescription("Tool for doing X.");
  parser.addHelpOption();
  parser.addVersionOption();
  parser.addPositionalArgument("infile",
      QCoreApplication::translate("main", "Input file."));

  QCommandLineOption verbose_opt("+",
      QCoreApplication::translate("main", "be verbose"));
  parser.addOption(verbose_opt);

  QCommandLineOption out_opt(QStringList() << "o" << "output",
      QCoreApplication::translate("main", "Output file."),
      QCoreApplication::translate("main", "filename"), // value name
      QCoreApplication::translate("main", "out")   // default value
      );
  parser.addOption(out_opt);

  // exits on error
  parser.process(app);

  const QStringList args = parser.positionalArguments();

  qDebug() << "Input files: " << args
    << ", verbose: " << parser.isSet(verbose_opt)
    << ", output: " << parser.value(out_opt)
    << '\n';
  return 0;
}

Przykładowe wyjście

Automatycznie generowany ekran pomocy:

$ ./qtopt -h
Usage: ./qtopt [options] infile
Tool for doing X.

Options:
  -h, --help               Displays this help.
  -v, --version            Displays version information.
  -+                       be verbose
  -o, --output   Output file.

Arguments:
  infile                   Input file.

Automatycznie generowane wyjście wersji:

$ ./qtopt -v
ToolX 1.2

Niektóre prawdziwe połączenia:

$ ./qtopt b1 -+ -o tmp blah.foo
Input files:  ("b1", "blah.foo") , verbose:  true , output:  "tmp"
$ ./qtopt          
Input files:  () , verbose:  false , output:  "out"

Błąd parsowania:

$ ./qtopt --hlp
Unknown option 'hlp'.
$ echo $?
1

Podsumowanie

Jeśli twój program używa już bibliotek Qt (>=5.2), jego interfejs API parsowania wiersza poleceń jest wystarczająco wygodny, aby wykonać zadanie.

Należy pamiętać, że wbudowane opcje Qt są zużywane przez QApplication przed uruchomieniem parsera opcji.

 5
Author: maxschlepzig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-12 10:56:00

Polecenie jest w zasadzie łańcuchem znaków. Ogólnie można go podzielić na dwie części - komendę name i komendę arguments.

Przykład:

ls

Jest używany do wyświetlania zawartości katalogu:

user@computer:~$ ls
Documents Pictures Videos ...

Powyższy plik ls jest wykonywany w folderze home użytkownika. Tutaj argument który folder do listy jest domyślnie dodawany do polecenia. Możemy jawnie przekazać niektóre argumenty:

user@computer:~$ ls Picture
image1.jpg image2.jpg ...

Tutaj wyraźnie powiedziałem ls które zawartość folderu, którą chciałbym zobaczyć. Możemy użyć innego argumentu na przykład l do wyświetlenia szczegółów KAŻDEGO pliku i folderu, takich jak uprawnienia dostępu, rozmiar itp.:

user@computer:~$ ls Pictures
-rw-r--r-- 1 user user   215867 Oct 12  2014 image1.jpg
-rw-r--r-- 1 user user   268800 Jul 31  2014 image2.jpg
...

Oh, rozmiar wygląda naprawdę dziwnie (215867, 268800). Dodajmy flagęh dla wyjścia przyjaznego człowiekowi:

user@computer:~$ ls -l -h Pictures
-rw-r--r-- 1 user user  211K Oct 12  2014 image1.jpg
-rw-r--r-- 1 user user  263K Jul 31  2014 image2.jpg
...

Niektóre polecenia pozwalają na łączenie ich argumentów (w powyższym przypadku równie dobrze możemy napisać ls -lh i otrzymamy to samo wyjście), używając krótkiego (Zwykle pojedynczej litery, ale czasami więcej; skrót) lub długie nazwy (w przypadku ls mamy -a lub --all do wyświetlania wszystkich plików, w tym ukrytych, z --all jest długą nazwą dla -a) itp. Istnieją polecenia, w których kolejność argumentów jest bardzo ważna, ale są też inne, w których kolejność argumentów nie jest w ogóle ważna.

Na przykład nie ma znaczenia czy używam ls -lh czy ls -hl jednak w przypadku mv (przenoszenie/zmiana nazwy plików) masz mniej elastyczność dla ostatnich dwóch argumentów, czyli mv [OPTIONS] SOURCE DESTINATION.

W celu opanowania poleceń i ich argumentów możesz użyć man (przykład: man ls) lub info (przykład: info ls).

W wielu językach, w tym w C / C++, można analizować argumenty linii poleceń, które użytkownik dołącza do wywołania pliku wykonywalnego (polecenia). Istnieje również wiele bibliotek dostępnych do tego zadania, ponieważ w jego rdzeniu nie jest tak łatwo zrobić to poprawnie i jednocześnie proponują dużą ilość argumentów i ich odmian:

  • getopt
  • argp_parse
  • gflags
  • ...

Każda aplikacja C / C++ ma tzw. punkt wejścia, czyli w zasadzie miejsce, w którym zaczyna się Twój kod-funkcję main:

int main (int argc, char *argv[]) { // When you launch your application the first line of code that is ran is this one - entry point
    // Some code here
    return 0; // Exit code of the application - exit point
}

Bez względu na to, czy korzystasz z biblioteki (jak jedna z wyżej wymienionych; ale to wyraźnie nie jest dozwolone w Twoim przypadku ;)) lub rób to samodzielnie twoja main funkcja ma dwa argumenty:

  • argc - reprezentuje liczbę argumentów
  • argv - wskaźnik do tablicy łańcuchów (można również zobaczyć char** argv, który jest zasadniczo taki sam, ale trudniejszy w użyciu).

Uwaga: main w rzeczywistości ma również trzeci argument char *envp[], który umożliwia przekazywanie zmiennych środowiskowych do Twojego polecenia, ale jest to bardziej zaawansowana rzecz i naprawdę nie sądzę, że jest to wymagane w Twoim przypadku.

Przetwarzanie argumenty wiersza poleceń składają się z dwóch części:

  1. Tokenizowanie - jest to część, w której każdy argument otrzymuje znaczenie. Jest to proces dzielenia listy argumentów na znaczące elementy (tokeny). W przypadku ls -l l jest nie tylko poprawnym znakiem, ale także tokenem samym w sobie, ponieważ reprezentuje kompletny, poprawny argument.

Oto przykład jak wypisać liczbę argumentów i (niezaznaczoną dla ważności) znaki, które mogą lub nie mogą być faktycznie argumentami:

#include <iostream>
using std::cout;
using std::endl;

int main (int argc, char *argv[]) {
    cout << "Arguments' count=%d" << argc << endl;

    // First argument is ALWAYS the command itself
    cout << "Command: " << argv[0] << endl;

    // For additional arguments we start from argv[1] and continue (if any)
    for (int i = 1; i < argc; i++) {
        cout << "arg[" << i << "]: " << argv[i] << endl;
    }

    cout << endl;
    return 0;
}
  1. Parsing - po pozyskaniu tokenów (argumentów i ich wartości) musisz sprawdzić, czy Twoje polecenie je obsługuje. Na przykład:

    user@computer:~$ ls -y
    

    Powróci

    ls: invalid option -- 'y'
    Try 'ls --help' for more information.
    

    To dlatego, że parsowanie nie powiodło się. Dlaczego? Ponieważ y (i -y odpowiednio; zauważ, że -, --, : itd. nie jest wymagane i jego do parsowania argumentów, czy chcesz, że rzeczy istnieje lub nie; w systemach Unix/Linux jest to swego rodzaju konwencja, ale nie jesteś z nią związany) jest nieznanym argumentem dla polecenia ls.

Dla każdego argumentu (jeśli zostanie pomyślnie rozpoznany jako taki) uruchamiasz jakąś zmianę w aplikacji. Możesz użyć if-else na przykład, aby sprawdzić, czy dany argument jest poprawny i co robi, a następnie zmienić cokolwiek chcesz, aby ten argument zmienił się w wykonaniu reszty kodu. You can go the old C-style lub c++-style:

* `if (strcmp(argv[1], "x") == 0) { ... }` - compare the pointer value
* `if (std::string(argv[1]) == "x") { ... }` - convert to string and then compare

Lubię (gdy nie używam biblioteki) konwertować argv na std::vector ciągów takich jak ten:

std::vector<std::string> args(argv, argv+argc);
for (size_t i = 1; i < args.size(); ++i) {
    if (args[i] == "x") {
        // Handle x
    }
    else if (args[i] == "y") {
        // Handle y
    }
    // ...
}

Część std::vector<std::string> args(argv, argv+argc); jest po prostu łatwiejszym sposobem obsługi tablicy łańcuchów w języku C++, ponieważ char * jest ciągiem w stylu C (z char *argv[] jest tablicą takich łańcuchów), które można łatwo przekonwertować na ciąg C++, który jest std::string. Następnie możemy dodać wszystkie skonwertowane ciągi znaków do wektora podając adres początkowy argv , a następnie również wskazując na jego ostatni adres to argv + argc (dodajemy argc numer łańcucha do adresu bazowego argv, który w zasadzie wskazuje na ostatni adres naszej tablicy).

Wewnątrz for pętli powyżej widać, że sprawdzam (używając prostego if-else), czy dany argument jest dostępny, a jeśli tak, to odpowiednio go obsługuję. Ostrzeżenie: używając takiej pętli kolejność argumentów nie ma znaczenia. Jak już wspomniałem na początku niektóre komendy faktycznie mają ścisły zamówienie na niektóre lub wszystkie ich argumenty. Można to zrobić w inny sposób, ręcznie wywołując zawartość każdego args (lub argv, jeśli użyjesz początkowego char* argv[], a nie rozwiązania wektorowego):

// No for loop!
if (args[1] == "x") {
    // Handle x
}
else if (args[2] == "y") {
    // Handle y
}
// ...

To daje pewność, że w pozycji 1 tylko x będą oczekiwane itp. Problem polega na tym, że możesz strzelić sobie w nogę, wychodząc poza granice z indeksowaniem, więc musisz upewnić się, że indeks pozostanie w zakresie ustalonym przez argc:

if (argc > 1 && argc <= 3) {
    if (args[1] == "x") {
        // Handle x
    }
    else if (args[2] == "y") {
        // Handle y
    }
}

Powyższy przykład zapewnia, że masz zawartość w indeksie 1 i 2, ale nie dalej.

Wreszcie, ale nie mniej ważne, obsługa każdego argumentu jest rzeczą, która całkowicie zależy od Ciebie. Możesz użyć FLAG logicznych, które są ustawiane po wykryciu określonego argumentu (przykład: if (args[i] == "x") { xFound = true; } i później w kodzie zrób coś na podstawie bool xFound i jego wartości), typów numerycznych, jeśli argument jest liczbą lub składa się z liczby wraz z nazwą argumentu (przykład: mycommand -x=4 posiada argument -x=4, który można dodatkowo przeanalizować jako x i 4 ostatni będący wartością x) itd. Na podstawie zadania pod ręką można zwariować i dodać szaloną ilość złożoności do argumentów wiersza poleceń.

Mam nadzieję, że to pomoże. Daj mi znać, jeśli coś jest niejasne lub potrzebujesz więcej przykładów.
 4
Author: rbaleksandar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-22 07:53:38

Polecam boost:: program_options, jeśli możesz użyć Boost lib.

Nie ma nic konkretnego w STL ani w zwykłych bibliotekach C++/C runtime.

 3
Author: Macke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-14 20:50:00

argstream jest bardzo podobny do boost.program_option: umożliwia wiązanie zmiennych z opcjami itp. Nie obsługuje jednak opcji przechowywanych w pliku konfiguracyjnym.

 3
Author: Luc Hermitte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-22 23:37:43

Możesz użyć już utworzonej biblioteki do tego

Http://www.boost.org/doc/libs/1_44_0/doc/html/program_options.html

 3
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-30 00:35:51

Wypróbuj bibliotekę CLPP. Jest to prosta i elastyczna biblioteka do parsowania parametrów wiersza poleceń. Tylko nagłówek i cross-platform. Używa tylko bibliotek ISO C++ i Boost C++. IMHO to jest łatwiejsze niż Boost.Program_options.

Biblioteka: http://sourceforge.net/projects/clp-parser/

26 października 2010-nowe wydanie 2.0 rc. Poprawiono wiele błędów, Poprawiono pełną refaktoryzację kodu źródłowego, dokumentację, przykłady i komentarze.

 3
Author: Denis Shevchenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-27 03:53:12
 2
Author: bobbymcr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-17 03:19:19