Пользовательские параметры командной строки - PullRequest
3 голосов
/ 24 января 2011

У меня проблема с параметрами командной строки.Я закончил программу, чтобы я мог запустить ее так из командной строки:

program.exe test.txt copy_test.txt

По сути, моя программа выполняет следующие действия:

  • вводит некоторый текстовый файл
  • сортирует его и копирует в новый текстовый файл

НО (всегда что, но ?!), я должен запустить программу из командной строки так:

program.exe -input=test.txt -output=copy_test.txt

И яне знаю как это сделать.Я исследовал, но не нашел никакой помощи: (

Пожалуйста, ответьте.

#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;

int main ( int argc, char* argv[])
{
 ifstream in(argv[1]);
 ofstream out(argv[2]);
 vector <string> sV;
 string line;
 while (in >> line)
  sV.push_back(line);
 for ( int i = 0; i < sV.size(); i++)
 sort ( sV.begin(), sV.end () );
 for ( int i = 0; i < sV.size(); i++)
 out << sV[i] << endl;
 cin.get();
 return 0;
}

Ответы [ 4 ]

7 голосов
/ 24 января 2011

Вы должны проанализировать main argv аргументы, чтобы проверить, начинаются ли они с -input, -output и т. Д. И т. Д.

Делать это с нуля - ад, но, к счастью, есть много полезных библиотек, например boost.program_options

0 голосов
/ 16 сентября 2016

Я немного опоздал на вечеринку с этим, но я предоставлю обновленный ответ. На самом деле вы можете получить ту функциональность, которая вам нужна в C ++, немного поработав с помощью 'getopt'. Используя getopt_long(), вы можете создавать либо односимвольные параметры (например, -c), либо именованные (например, --input). Вы также можете использовать getopt_long_only(), что позволит вам передавать именованные опции только с одной чертой. См. Например здесь или этот ответ .

Пример

Вот пример, который должен выполнить то, что вы пытаетесь сделать:

#include <iostream>
#include <getopt.h>
#include <map>
#include <string>

int main (int argc, char** argv)
{
    // Create the variables to store your parameters
    std::map<std::string, std::string> input_parameters ;
    input_parameters["input"] = "default_in" ;   // Storage for input
    input_parameters["output"] = "default_out" ; // Storage for output

    // Create variables to hold your parameters
    const struct option longopts[] =
    {
        {"input", required_argument, 0, 'i'},
        {"output", required_argument, 0, 'o'},
        {0,0,0,0} // This tells getopt that this is the end
    };

    // Some parameters for getopt_long
    int c(0);

    // Get the options from the command line
    while (c != -1) {
        int option_index(-1) ;

        // Read the next command line option
        // Note here that the ':' after the 'i' and 'o' denotes that
        // it requires an argument
        c = getopt_long(argc, argv, "i:o:", longopts, &option_index) ;

        // If the option is valid, fill the corresponding value
        if ((c>0)&&(option_index>=0)) {
            std::cout << option_index << std::endl;
            input_parameters[longopts[option_index].name] = optarg ;
        }

        switch (c) {
            case 'i':
                // Fill input option
                input_parameters["input"] = optarg ;
            case 'o':
                // Fill output option
                input_parameters["output"] = optarg ;
            case '?':
                // getopt_long printed an error message
                break ;
        }
    }

    std::cout << "input  = " << input_parameters["input"] << std::endl;
    std::cout << "output = " << input_parameters["output"] << std::endl;

    return 0 ;
}

Обратите внимание, что здесь вы должны выполнить это, оставив пробел между параметром и значением, которое вы хотите передать ему. Это даст следующее:

$ ./myscript --input inputfile.txt --output outputfile.txt
input  = inputfile.txt
output = outputfile.txt

или

$ ./myscript -i inputfile.txt -o outpufile.txt
input  = inputfile.txt
output = outputfile.txt

Вы также можете использовать --input и -i взаимозаменяемо (аналогично --output и -o).

Начните бесстыдный плагин (мой собственный CLOptions код, построенный на основе getopt)

На самом деле я был немного недоволен количеством работы, которое потребовалось, чтобы получить полную функциональность getopt с параметрами, которые могут быть либо логическими, double, int или string. Мне также пришлось создать совершенно новую реализацию в КАЖДОМ ПРОЕКТЕ! Итак, вместо этого я собрал быстрый класс под названием «CLOptions», чтобы я мог #include "CLOptions.h" в своем коде (все в одном файле), и теперь мне нужна только одна строка для определения каждой дополнительной опции. Он также создает опции -h или -help для печати справочной информации для вас! Он включает в себя функциональность для получения каждого параметра как bool, double, int или string в зависимости от того, как вы определяете каждый параметр. Вы можете взглянуть на это на GitHub здесь с примером , как вышеуказанный метод может быть реализован . Обратите внимание, что класс C ++ 11 и для него потребуется -std=c++11 во время компиляции (хотя, если кто-то спросит, я могу попытаться кодировать версию C).

Хотя я не пробовал их, есть также множество других программ командной строки, которые были разработаны другими людьми для решения этой проблемы (например, options или dropt ) , Вы, вероятно, можете найти их, погуглив вокруг.

0 голосов
/ 24 января 2011

Ну, с вашими новыми аргументами формата вы не можете просто передать их как есть конструкторам потока.

Вам придется проверить, начинаются ли они с определенной строки, например, с strncmp, а затем передать адрес соответствующего бита, например argv[1]+8, для типа ввода.

Поскольку вы предоставляете префиксы типа --input=, вы также можете учитывать возможность того, что они могут быть в другом порядке.

Например, вы можете заменить:

int main (int argc, char* argv[]) {
    ifstream in(argv[1]);
    ofstream out(argv[2]);

с чем-то вроде:

int main (int argc, char* argv[]) {
    char *infile = 0;
    char *outfile = 0;
    for (int i = 1; i < argc; i++) {
        if (strncmp (argv[i], "--input=", 8) == 0) {
            infile = argv[i] + 8;
        } else {
            if (strncmp (argv[i], "--output=", 9) == 0) {
                outfile = argv[i] + 9;
            } else {
                std::cerr << "Invalid argument [" << argv[i] << "]" << std::endl;
                return -1;
            }
        }
    }
    if ((infile == 0) || (outfile == 0)) {
        std::cerr << "Need to specify input and output file" << std::endl;
        return -1;
    }

    ifstream in(infile);
    ofstream out(outfile);
0 голосов
/ 24 января 2011

Вы могли бы избавить опытных пользователей от необходимости вводить ненужный текст каждый раз, когда они запускают вашу программу, и вместо этого предлагать ключ -help, который отображает использование.

Этот подход обычно используется в большинстве программ командной строки и является причиной, по которой многие энтузиасты командной строки ценят простоту и мощь командной строки.

Другой вариант - предложить оба метода., так как некоторые пользователи могут предпочесть более длинный метод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...