简体   繁体   English

自定义命令行参数

[英]Custom Command Line Parameters

I have a problem with command line parameters. 我的命令行参数有问题。 I finished the program so I can start it like this from command line: 我完成了程序,所以我可以从命令行启动它:

program.exe test.txt copy_test.txt

Basically, my program does the following : 基本上,我的程序执行以下操作:

  • inputs some text file 输入一些文本文件
  • sorts it and copy to a new text file 对其进行排序并复制到新的文本文件

BUT (always that but?!), I should start the program from command line like this: 但是(总是这样但是?!),我应该从命令行启动程序,如下所示:

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

And I don't know how to do that. 我不知道该怎么做。 I researched, but I didn't find any help :( 我研究过,但我没有找到任何帮助:(

Please respond. 请回复。

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

You should parse main 's argv arguments in order to check whether they start by -input , -output etc etc. 你应该解析mainargv参数,以便检查它们是否以-input-output等开始。

Doing this from scratch is a hell, but luckily there are many useful libraries to do this, like boost.program_options 从头开始这样做是一个地狱,但幸运的是有很多有用的库可以做到这一点,比如boost.program_options

I'm a bit late to the party with this, but I'll provide an updated answer. 我有点迟到了,但我会提供一个更新的答案。 You can actually get the functionality that you want in C++ with a little work using 'getopt'. 您可以使用'getopt'实际获得C ++中所需的功能。 Using getopt_long() you can create either single character options (like -c ) or named options (like --input ). 使用getopt_long()可以创建单个字符选项(如-c )或命名选项(如--input )。 You can also use getopt_long_only() which will allow you to pass named options with only a single dash. 您还可以使用getopt_long_only() ,这将允许您只使用一个破折号传递命名选项。 See for example here or this answer . 例如,请参阅此处此答案

Example

Here is an example that should accomplish what you're trying to do: 这是一个应该完成你要做的事情的例子:

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

Note that here, you would run this leaving a space between the parameter and the value you want to pass to it. 请注意,在这里,您将运行此参数,在参数和要传递给它的值之间留一个空格。 This will produce the following: 这将产生以下结果:

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

or 要么

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

You can also use --input and -i interchangeably (similarly with --output and -o ). 您也可以交替使用--input-i (与--output-o类似)。

Begin shameless plug (my own CLOptions code that is built around getopt) 开始无耻的插件 (我自己的CLOptions代码是围绕getopt构建的)

I was actually a little disgruntled with the amount of work it took to get the full blown functionality of getopt with parameters that could be either boolean, double, int, or string. 实际上,我对使用boopt,double,int或string参数获取getopt的完整功能所花费的工作量有点不满。 I also had to create an entirely new implementation in EVERY PROJECT! 我还必须在每个项目中创建一个全新的实现! So, instead I put together a quick class called "CLOptions" so I could #include "CLOptions.h" in my code (everything is in a single file) and now I only need one line to define each additional option. 所以,我把一个名为“CLOptions”的快速类放在一起,这样我就可以在我的代码中#include "CLOptions.h" (一切都在一个文件中),现在我只需要一行来定义每个附加选项。 It also creates the -h or -help options for printing help information for you! 它还会为您打印帮助信息的-h-help选项! It includes functionality for getting each parameter as either a bool, double, int, or string depending on how you define each parameter. 它包括将每个参数作为bool,double,int或string的功能,具体取决于您定义每个参数的方式。 You can take a look at it on GitHub here with an example of how the above method could be implemented . 您可以在GitHub上查看它,并举例说明如何实现上述方法 Note that the class is C++11 and will require the -std=c++11 at compile time (although if someone asks, I can try and code up a C version). 请注意,该类是C ++ 11,并且在编译时需要-std=c++11 (尽管如果有人问,我可以尝试编写C版本)。

Although I haven't tried them, there's also a host of other command line programs that have been designed by other people to solve this problem (for example options or dropt ). 虽然我还没有尝试过,但是还有许多其他命令行程序由其他人设计来解决这个问题(例如选项dropt )。 You can probably find them by googling around. 你可以通过谷歌搜索找到它们。

You could eliminate the need for advanced users to have to type unnecessary text each time they run your program and instead offer a -help switch that displays usage. 您可以消除高级用户每次运行程序时必须键入不必要的文本的需要,而是提供显示用法的-help开关。

This is generally the approach most command line programs take, and is the reason why many command line enthusiasts appreciate the simplicity and power of the command line. 这通常是大多数命令行程序采用的方法,也是许多命令行爱好者欣赏命令行的简单性和强大功能的原因。

Another option would be to offer both methods, as some users may prefer the longer method. 另一种选择是提供两种方法,因为一些用户可能更喜欢更长的方法。

Well, with your new format arguments, you can't just pass them as-is to the stream constructors. 好吧,使用新的格式参数,您不能只是按原样将它们传递给流构造函数。

You will have to check if they start with a specific string, such as with strncmp and then pass the address of the relevant bit such as argv[1]+8 for the input type. 您必须检查它们是否以特定字符串开头,例如使用strncmp ,然后为输入类型传递相关位的地址,例如argv[1]+8

Since you're providing --input= type prefixes, you may also want to handle the possibility that they may be in the other order as well. 由于您提供了--input= type前缀,因此您可能还希望处理它们可能处于其他顺序的可能性。

For example, you can replace: 例如,您可以替换:

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

with something like: 有类似的东西:

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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM