[英]C Split CMD Arguments
我正在尝试做某事,但是我可以。 我在C中有一个程序,我想在其中解析所有参数。 让我们更具体一点
编辑 :我在缓冲区中读取命令,而不是在程序以argv等启动时读取。我从STDIN使用fgets读取命令
假设我阅读了这样的命令行:
ls -la
我想以这种格式将命令和参数列表保存在n
数组中:
char ***command; // A list of lists of strings.
command[0][0] = "ls";
command[0][1] = "-l";
command[0][2] = "a";
command[0][3] = NULL;
我想使用execvp执行上述命令,这就是为什么我想要这种格式。 还看看下面的例子
ls -la | grep 1
数组必须为以下内容:
command[0][0] = "ls";
command[0][1] = "-l";
command[0][2] = "a";
command[0][3] = NULL;
command[1][0] = "grep";
command[1][1] = 1;
command[1][2] = NULL;
因此,我想简单地将命令拆分并基于字符|将它们放入2D数组中。 但也要保留命令参数。
我尝试使用strtok(空格字符分隔符)来执行此操作,然后将它们存储在数组中,但失败了。
你能帮我吗?
谢谢
下面的答案显示了如何像将shell一样将C字符串拆分为argc
和argv
传递给main
函数之前,如何进行拆分。 即ls -la
将被拆分为:
argv[0] == "ls"
argv[1] == "-la"
但是,由于要包括多个由竖线字符粘贴在一起的命令行,因此必须首先在每个|
字符串处拆分字符串。 字符。 您可以使用strtok
完成此操作。
str = "ls -la|grep hello";
...
// Do split on |
...
strs[0] == "ls -la";
strs[1] == "grep hello";
然后将这些命令行进一步拆分为自己的argv
数组。 然后,按照您的描述,将它们最终组装成一个具有NULL
分隔符的数组。
由于您在开始时不知道最终数组的大小。 或者在这方面多少|
如果有迹象表明,您可以首先对它们进行计数并分配一个包含所有argv
的数组:
char **strs = NULL;
char **argvs = NULL;
size_t count = 0;
size_t i = 0;
while (*str) if (*str++ == '|') ++count;
strs = calloc(count, sizeof(char *));
...
// strtok on | and save tokens into strs[i]
...
现在拆分命令行,并在末尾附加NULL
:
// Code for split_commandline below.
for (i = 0; i < count; i++)
{
argvs[i] = split_commandline(strs[i], &argc);
// Make room for NULL at the end of the argv array.
argvs[i] = realloc(argvs[i], (argc + 1) * sizeof(char *));
argvs[i][argc] = NULL;
}
一切都是人为的,当然可以使用存储,但是这样做的步骤很明确。
注意 :这不会将"ls -la"
拆分为原始问题所要求的"ls", "-l", "a"
,而是"ls", "-la"
。 我不确定为什么会这样,但是由于"-la"
含义是ls
程序特有的,因此需要对单个命令进行修改。
Unix / Linux您可以使用wordexp
进行此操作。 但是,这并不意味着您应该意识到一些安全隐患。 也就是说,它将扩展shell变量,并且如果不是全部,则许多实现将导致对sh
的调用。
注:似乎OSX 10.9.5泄漏内存wordexp
即使wordfree
被调用。 请参见是否知道OSX 10.9.5的libc中的wordexp泄漏? 有关详细信息。
Windows我知道这个问题仅针对Linux。 但是其他人可能对多平台解决方案感兴趣。
在这里您可以使用CommandLineToArgvW
。 请注意,这是针对wchar_t *
因此下面的示例代码首先将char *
转换为wchar_t *
,进行分割,然后再转换回char *
以获得两种平台的一致API。
编写__getmainargs
此实现后,我还找到了__getmainargs
,它支持char *
,但是我没有尝试使用它。
代码示例:
char **split_commandline(const char *cmdline, int *argc)
{
size_t i;
char **argv = NULL;
assert(argc);
if (!cmdline)
{
return NULL;
}
// Posix.
#ifndef _WIN32
{
int ret;
wordexp_t p;
memset(&p, 0, sizeof(p));
// Note! This expands shell variables (might be a security issue).
if ((ret = wordexp(cmdline, &p, 0)))
{
return NULL;
}
*argc = p.we_wordc;
if (!(argv = calloc(*argc, sizeof(char *))))
{
goto fail;
}
for (i = 0; i < p.we_wordc; i++)
{
if (!(argv[i] = strdup(p.we_wordv[i])))
{
goto fail;
}
}
// Note that on some OSX versions this does not free all memory (10.9.5)
wordfree(&p);
return argv;
fail:
p.we_offs = 0;
wordfree(&p);
}
#else // WIN32
{
// TODO: __getmainargs is an alternative... https://msdn.microsoft.com/en-us/library/ff770599.aspx
wchar_t **wargs = NULL;
size_t needed = 0;
wchar_t *cmdlinew = NULL;
size_t len = strlen(cmdline) + 1;
if (!(cmdlinew = calloc(len, sizeof(wchar_t))))
{
goto fail;
}
if (!MultiByteToWideChar(CP_ACP, 0, cmdline, -1, cmdlinew, len))
{
goto fail;
}
if (!(wargs = CommandLineToArgvW(cmdlinew, argc)))
{
goto fail;
}
if (!(argv = calloc(*argc, sizeof(char *))))
{
goto fail;
}
// Convert from wchar_t * to ANSI char *
for (i = 0; i < *argc; i++)
{
// Get the size needed for the target buffer.
// CP_ACP = Ansi Codepage.
needed = WideCharToMultiByte(CP_ACP, 0, wargs[i], -1,
NULL, 0, NULL, NULL);
if (!(argv[i] = malloc(needed)))
{
goto fail;
}
// Do the conversion.
needed = WideCharToMultiByte(CP_ACP, 0, wargs[i], -1,
argv[i], needed, NULL, NULL);
}
if (wargs) LocalFree(wargs);
free(&cmdlinew);
return argv;
fail:
if (wargs) LocalFree(wargs);
free(&cmdlinew);
}
#endif // WIN32
if (argv)
{
for (i = 0; i < *argc; i++)
{
if(argv[i]) free(argv[i]);
argv[i] = NULL;
}
free(argv);
}
return NULL;
}
*使用getopt ... 有关 getopt的 更多信息,请通过 “第3个人getopt” *
int main (int argc, char **argv)
{
int opt, flgl = 0, flga = 0;
int indx;
while ((opt = getopt (argc, argv, "la")) != ERROR) {
switch (opt) {
case 'l':
flgl = 1; //printf ("%c", opt);
break;
case 'a':
flga = 1; //printf ("%c", opt);
break;
default:
fprintf (stderr, "missing file operand\n");
break;
}
}
if (optind >= argc) {
fprintf (stderr, "missing file operand\n");
return FAILURE;
}
for (indx = optind ; indx < argc ; indx++)
call_rm (argv[indx], flgd, flgr);
return SUCCESS;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.