Parsowanie argumentów linii poleceń w C++? [zamknięte]
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:
30 answers
Boost.Program_options should do the trick
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;
}
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; }
}
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
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;
}
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.
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.
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);
}
}
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.
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/
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.
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.]
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ą.
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...
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.
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;
}
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 .
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
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. :-)
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
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.
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.
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.
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.
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:
-
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;
}
-
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 polecenials
.
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ń.
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.
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.
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
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.
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
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