- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在编写一段代码来解析文本文件中的一些命令,我发现我认为这是 getopt 中的一个错误。只是想知道是否有人以前看过这个?
基本上我有一个循环,在每次迭代中我读取一个字符串,我用“strtok”将它转换为可以提供给 getopt 的东西并检查提供的选项。它在某些情况下有效:
$ ./test_short
cmd -ia
-- option i
-- option a
cmd -a
-- option a
cmd -i
-- option i
但它失败了,例如:
$ ./test_short
cmd -ia
-- option i
-- option a
cmd -i -a
cmd: invalid option -- '-'
-- option unknown
-- option a
-- option a
代码可以从https://github.com/angel-devicente/test-getopt中克隆出来,但为了完整起见,我也将简短选项放在下面。
是否知道这是一个真正的错误,还是有一些我忘记重置的其他全局变量?
谢谢,
#include <stdio.h> /* for printf */
#include <stdlib.h> /* for exit */
#include <string.h>
#include <unistd.h>
#define MAX_ARGS 10
#define MAX_C 100
int main(int argc, char **argv) {
int c;
char cmd[MAX_C+1];
int argc_i;
char *argv_i[MAX_ARGS];
while (1) {
// Read string, for example: cmd -i -a
fgets(cmd,MAX_C,stdin);
cmd[strlen(cmd) - 1] = 0;
if (strlen(cmd) <= 1) break;
// Transform into argc_i, argv_i, to feed to getopt
argc_i = 0;
char *p2 = strtok(cmd, " ");
while (p2 && argc_i < MAX_ARGS)
{
argv_i[(argc_i)++] = p2;
p2 = strtok(NULL, " ");
}
argv_i[argc_i] = 0;
// Reset getopt
optind = 1;
int option_index = 0;
while (1) {
c = getopt(argc_i, argv_i, "ia");
if (c == -1)
break;
switch (c) {
case 'a':
printf(" -- option a\n");
break;
case 'i':
printf(" -- option i\n");
break;
case '?':
printf(" -- option unknown\n");
break;
default:
printf("?? getopt returned character code 0%o ??\n", c);
}
}
printf("\n\n");
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
}
exit(EXIT_SUCCESS);
}
最佳答案
这看起来像是有意偏离 getopt
的 POSIX 规范。
首先,我更改了您代码中的这一行:
argv_i[(argc_i)++] = p2;
对此:
argv_i[(argc_i)++] = strdup(p2);
并将此添加到 while (1)
循环的末尾:
for (i=0;i<argc_i;i++) {
free(argv_i[i]);
}
并将其添加到顶部:
内存集(argv_i,0,sizeof(argv_i));
然后我运行了 valgrind:
==54748== Memcheck, a memory error detector
==54748== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==54748== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==54748== Command: ./x1
==54748==
optind=1
cmd -ia
arg 0: cmd
arg 1: -ia
-- option i
-- option a
cmd -i -a
==54748== Invalid read of size 1
==54748== at 0x4F192A1: _getopt_internal_r (in /usr/lib64/libc-2.17.so)
==54748== by 0x4F1A56A: _getopt_internal (in /usr/lib64/libc-2.17.so)
==54748== by 0x4F1A5B7: getopt (in /usr/lib64/libc-2.17.so)
==54748== by 0x400A2E: main (x1.c:48)
==54748== Address 0x5205093 is 3 bytes inside a block of size 4 free'd
==54748== at 0x4C2AF9D: free (vg_replace_malloc.c:540)
==54748== by 0x400B25: main (x1.c:89)
==54748== Block was alloc'd at
==54748== at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==54748== by 0x4EC3AA9: strdup (in /usr/lib64/libc-2.17.so)
==54748== by 0x400991: main (x1.c:31)
==54748==
-- option i
-- option a
由于在测试程序中没有对 malloc 内存的引用,这意味着 getopt
实现保留了一个指向它的指针。
现在让我们看一下 https://github.com/lattera/glibc/blob/master/posix/getopt.c 中的几行包括 _getopt_internal_r
:
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to 'getopt'.
On entry to 'getopt', zero means this is the first call; initialize.
When 'getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, 'optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* 1003.2 says this must be 1 before any call. */
int optind = 1;
...
static struct _getopt_data getopt_data;
...
int
_getopt_internal_r (int argc, char **argv, const char *optstring,
const struct option *longopts, int *longind,
int long_only, struct _getopt_data *d, int posixly_correct)
{
int print_errors = d->opterr;
if (argc < 1)
return -1;
d->optarg = NULL;
if (d->optind == 0 || !d->__initialized)
optstring = _getopt_initialize (argc, argv, optstring, d, posixly_correct);
...
int
_getopt_internal (int argc, char **argv, const char *optstring,
const struct option *longopts, int *longind, int long_only,
int posixly_correct)
{
int result;
getopt_data.optind = optind;
getopt_data.opterr = opterr;
result = _getopt_internal_r (argc, argv, optstring, longopts,
longind, long_only, &getopt_data,
posixly_correct);
optind = getopt_data.optind;
optarg = getopt_data.optarg;
optopt = getopt_data.optopt;
return result;
}
#define GETOPT_ENTRY(NAME, POSIXLY_CORRECT) \
int \
NAME (int argc, char *const *argv, const char *optstring) \
{ \
return _getopt_internal (argc, (char **)argv, optstring, \
0, 0, 0, POSIXLY_CORRECT); \
}
#ifdef _LIBC
GETOPT_ENTRY(getopt, 0)
GETOPT_ENTRY(__posix_getopt, 1)
#else
GETOPT_ENTRY(getopt, 1)
#endif
在这里我们可以看到 optind
被初始化为 1 和一个未初始化的内部静态结构。还有一条评论说 “在进入 'getopt' 时,零表示这是第一个调用;初始化。” 表示不同的初始化条件。
getopt
调用 getopt_internal
,随后将 optind
分配给静态结构的相应成员,然后将其传递给 _getopt_internal_r
。 _getopt_internal_r
函数然后检查结构的 optind
成员是否为 0 或 __initialized
成员是否为 0,如果是,则初始化函数被调用,定义如下:
static const char *
_getopt_initialize (int argc _GL_UNUSED,
char **argv _GL_UNUSED, const char *optstring,
struct _getopt_data *d, int posixly_correct)
{
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
if (d->optind == 0)
d->optind = 1;
d->__first_nonopt = d->__last_nonopt = d->optind;
d->__nextchar = NULL;
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
d->__ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
d->__ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct || !!getenv ("POSIXLY_CORRECT"))
d->__ordering = REQUIRE_ORDER;
else
d->__ordering = PERMUTE;
d->__initialized = 1;
return optstring;
}
我们可以在这里看到,如果 optind
成员当前为 0,则该成员将被设置为 1。另外,请特别注意这一行:
d->__nextchar = NULL;
如果我们再看看 https://github.com/lattera/glibc/blob/master/posix/getopt_int.h在定义此字段的位置,我们看到以下内容:
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
char *__nextchar;
所以这个变量跟踪处理停止的地方。但是回到 _getopt_internal_r
if (d->optind == 0 || !d->__initialized)
optstring = _getopt_initialize (argc, argv, optstring, d, posixly_correct);
只有当 optind
为 0 时才会发生重置。
因此在此实现中,将optind
设置为0 将重置处理。然而,这不是可移植的,因为 POSIX 指定这样做是未指定的行为。
这意味着要么将此代码更改为将 optind == 1
作为初始化条件,要么更新文档以反射(reflect)与 POSIX 标准的这种偏差并声明这是一种偏差.
关于c - 非全局使用的 getopt (C) 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65291405/
是否可以将参数传递给通过 getopt::long 调用的子例程?例如,当用户在命令行上指定 script.pl -pandora argument 时,我有此代码调用 &Salt GetOption
我正在尝试将 getopts 用于 bash 脚本。这个脚本可以有标志,所有这些标志都是强制性的,需要包含一个值。当本应包含值的强制标志之一为空时,getopts 使用下一行标志作为其内容。我该如何防
我公司使用 Getopt::Declare 作为其命令行选项解析器。我们的期权处理 block 的结构通常如下所示: Readonly my $ARGS => Getopt::Declare->new
我有一个带有可能的命令行参数的字符串(使用 Read-Eval-Print-Loop 程序),我希望它在传递给 Getopt::Long 时被解析为类似于命令行参数。 详细说明: 我有一个字符串 $s
我刚刚在代码审查中第一次被要求检查对 GetOptions() 的调用的返回码。 Getopt::Long 的功能Perl 模块。 我不记得曾经看到过这样的 GetOptions() 测试。功能。 那
我有这个 getopt: GetOptions( GetOptions ("library=s" => \@libfiles); @libfiles = split(/,/,join(','
我想使用 Getopt::Long::GetOptions 获取脚本的命令行选项。 我有这样的需求: perl script.pl -c -c -m argument 这里我们有选项标志 -c
我正在尝试使用 getopt() 解析命令行参数。下面是我的代码。无论我在运行程序时传递什么参数,getopt() 总是返回 -1。 例如: $ gcc -o test test.c $ ./test
在我的 python 脚本中使用 getopt.getopt() 函数时,临时返回值保持为空。我缺少什么。 def ParseOpts(cmdName): shortForm = 'c:n:'
我想使用 getopt,但它行不通。 它给了我 gcc -g -Wall -std=c99 -ftrapv -O2 -Werror -Wshadow -Wundef -save-temps -Werr
有人可以帮助我使用 getopt 函数吗? 当我在 main 中执行以下操作时: char *argv1[] = {"testexec","-?"}; char *argv2[] = {"testex
我有一个脚本,它从 CLI 获取 3 个输入变量并将其分别插入到 3 个变量: GetOptions("old_path=s" => \$old_path, "var=s" =
如何以这种方式接受命令行参数: ./a.out --printall 所以在我的程序中,我有类似的东西 if (printall) { // do something } 我不想这样做: if (
在 Perl getopts 中,是否可以多次使用相同的选项但具有不同的值?我想为用户提供输入不同网格坐标的选项,但使用相同的选项名称以尽量减少混淆。 例如: my_grid.pl --coords=
是否有用于Groovy的标准或推荐的getopts库,该库可以让我快速处理Groovy中的长期和短期命令行争论? groovy foo.groovy --fname = foo.txt --outpu
use Getopt::Long::Configure(pass_through); # .... GetOptions( "display=s" => \$display,
我正在运行 bash 4.2 版,我正在尝试使用内置命令 getopts 解析命令行参数, 但是getopts好像没有正确解析,如果-s不是第一个参数,就不会被解析 -s 未解析: %> ./geto
GetOptions( "r|repo=s" => \$repo, "R|list-repos" => \$list, ); 当我用 -r qwe 调用这个脚本
我正在尝试使用 getopt() 从 PHP7 cli 获取选项,但是在调用 php myprocess.php task -d -o 时我得到一个空数组。不知道我错过了什么,希望你能帮助我。 这就是
我正在寻找一种方法来处理包含必须解析的空格的参数 通过 shell getopts 命令。 while getopts ":a:i:o:e:v:u:" arg do echo "ARG is:
我是一名优秀的程序员,十分优秀!