我有一个程序,它接受各种命令行参数。为简化起见,我们会说它需要3个标志-a
,-b
和-c
,并使用以下代码来解析我的参数:
int c;
while((c = getopt(argc, argv, ":a:b:c")) != EOF)
{
switch (c)
{
case 'a':
cout << optarg << endl;
break;
case 'b':
cout << optarg << endl;
break;
case ':':
cerr << "Missing option." << endl;
exit(1);
break;
}
}
注意:a和b在标志后面带参数。
但如果我用
调用我的程序,我会遇到一个问题./myprog -a -b parameterForB
我忘记了parameterForA,parameterForA(由optarg表示)返回为-b
,parameterForB被认为是没有参数的选项,optind被设置为argv中parameterForB的索引。
在这种情况下,期望的行为是在':'
找不到参数后返回-a
,并且Missing option.
被打印为标准错误。但是,只有在-a
是传递给程序的最后一个参数的情况下才会发生这种情况。
我想问题是:有没有办法让getopt()
假设没有选项会以-
开头?
答案 0 :(得分:11)
请参阅getopt
getopt
。它说
如果[getopt]检测到丢失 option-argument,它将返回 冒号(':')如果是第一个 optstring的字符是冒号,或 问号字符('?') 否则。
至于那种检测,
- 如果该选项是指向的字符串中的最后一个字符 argv的元素,然后是optarg 包含argv的下一个元素,和 optind应增加2.如果 由此产生的optind值 大于argc,这表示a 缺少option-argument和getopt() 应返回错误指示。
- 否则,optarg将指向该选项后面的字符串 argv元素中的字符,和 optind应增加1。
醇>
看起来*optarg
的定义不是为了做你想做的事情,所以你必须自己实施检查。幸运的是,您可以通过检查optind
并自行更改int c, prev_ind;
while(prev_ind = optind, (c = getopt(argc, argv, ":a:b:c")) != EOF)
{
if ( optind == prev_ind + 2 && *optarg == '-' ) {
c = ':';
-- optind;
}
switch ( …
来实现这一目标。
{{1}}
答案 1 :(得分:7)
如果您使用的是C ++,我建议使用boost :: program_option来解析命令行参数:
答案 2 :(得分:4)
完全披露:我不是这方面的专家。
来自gnu.org的this example会有用吗?它似乎处理'?'在未提供预期参数的情况下的字符:
while ((c = getopt (argc, argv, "abc:")) != -1)
switch (c)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
更新: 也许以下内容可以作为修复工具使用?
while((c = getopt(argc, argv, ":a:b:c")) != EOF)
{
if (optarg[0] == '-')
{
c = ':';
}
switch (c)
{
...
}
}
答案 3 :(得分:2)
作为无Boost项目的替代方案,我有getopt
的简单头文件C ++包装器(在BSD 3条款许可下):https://github.com/songgao/flags.hh
取自回购中的example.cc
:
#include "Flags.hh"
#include <cstdint>
#include <iostream>
int main(int argc, char ** argv) {
uint64_t var1;
uint32_t var2;
int32_t var3;
std::string str;
bool b, help;
Flags flags;
flags.Var(var1, 'a', "var1", uint64_t(64), "This is var1!");
flags.Var(var2, 'b', "var2", uint32_t(32), "var2 haahahahaha...");
flags.Var(var3, 'c', "var3", int32_t(42), "var3 is signed!", "Group 1");
flags.Var(str, 's', "str", std::string("Hello!"), "This is a string, and the description is too long to fit in one line and has to be wrapped blah blah blah blah...", "Group 1");
flags.Bool(b, 'd', "bool", "this is a bool variable", "Group 2");
flags.Bool(help, 'h', "help", "show this help and exit", "Group 3");
if (!flags.Parse(argc, argv)) {
flags.PrintHelp(argv[0]);
return 1;
} else if (help) {
flags.PrintHelp(argv[0]);
return 0;
}
std::cout << "var1: " << var1 << std::endl;
std::cout << "var2: " << var2 << std::endl;
std::cout << "var3: " << var3 << std::endl;
std::cout << "str: " << str << std::endl;
std::cout << "b: " << (b ? "set" : "unset") << std::endl;
return 0;
}
答案 4 :(得分:1)
有很多不同版本的getopt
,所以即使你可以让它适用于一个版本,也可能至少有五个其他版本的解决方法会破解。除非你有一个压倒性的理由使用getopt,否则我会考虑别的东西,比如Boost.Program_options。