[英]C Split CMD Arguments
I'm trying to do something but i can. 我正在尝试做某事,但是我可以。 I have a program in C in which i want to parse all the arguments.
我在C中有一个程序,我想在其中解析所有参数。 Let's be more specific
让我们更具体一点
EDIT : I read the command in buffer and not when the program starts with argv etc. i read the command using fgets from STDIN 编辑 :我在缓冲区中读取命令,而不是在程序以argv等启动时读取。我从STDIN使用fgets读取命令
Let's say that i read a command line like this one: 假设我阅读了这样的命令行:
ls -la
I want to save the list of the commands and arguments in n
arrays in this format: 我想以这种格式将命令和参数列表保存在
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;
I want to execute the above commands using execvp thats why i wanted in this format. 我想使用execvp执行上述命令,这就是为什么我想要这种格式。 Also take a look at the following example
还看看下面的例子
ls -la | grep 1
The array must be the following: 数组必须为以下内容:
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;
So in a few words i want to split the commands and put them in 2D Array Based on the character | 因此,我想简单地将命令拆分并基于字符|将它们放入2D数组中。 but maintain the command arguments as well.
但也要保留命令参数。
I tried to do that using strtok (space char delimeter) and then store them in the array but i failed. 我尝试使用strtok(空格字符分隔符)来执行此操作,然后将它们存储在数组中,但失败了。
Can you help me please? 你能帮我吗?
Thank you 谢谢
The below answer shows how you can split up a C string just as the shell would do before passing it on to the main
function as argc
and argv
. 下面的答案显示了如何像将shell一样将C字符串拆分为
argc
和argv
传递给main
函数之前,如何进行拆分。 That is ls -la
would be split into: 即
ls -la
将被拆分为:
argv[0] == "ls"
argv[1] == "-la"
However since you want to include multiple command lines stuck together with pipe characters, you would first have to split the string at each |
但是,由于要包括多个由竖线字符粘贴在一起的命令行,因此必须首先在每个
|
字符串处拆分字符串。 character. 字符。 This can be done using
strtok
as you mention. 您可以使用
strtok
完成此操作。
str = "ls -la|grep hello";
...
// Do split on |
...
strs[0] == "ls -la";
strs[1] == "grep hello";
And then further split those command lines into their own argv
arrays. 然后将这些命令行进一步拆分为自己的
argv
数组。 Then finally assemble those into the one array with NULL
delimeters as you described. 然后,按照您的描述,将它们最终组装成一个具有
NULL
分隔符的数组。
Since you don't know the size of the final array when you start out. 由于您在开始时不知道最终数组的大小。 Or for that matter how many
|
或者在这方面多少
|
signs there is, you could first of all count those and allocate an array holding all the argv
s: 如果有迹象表明,您可以首先对它们进行计数并分配一个包含所有
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]
...
Now split the command lines and append the NULL
at the end: 现在拆分命令行,并在末尾附加
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;
}
All a bit contrived and can of course be made to use storage, but this does it in clear steps. 一切都是人为的,当然可以使用存储,但是这样做的步骤很明确。
NOTE : This does not split "ls -la"
into "ls", "-l", "a"
as the original question asked for, but rather "ls", "-la"
. 注意 :这不会将
"ls -la"
拆分为原始问题所要求的"ls", "-l", "a"
,而是"ls", "-la"
。 I'm not sure why this would be desired, but it would need hacks for individual commands since what "-la"
means is specific to the ls
program. 我不确定为什么会这样,但是由于
"-la"
含义是ls
程序特有的,因此需要对单个命令进行修改。
Unix/Linux You can use wordexp
for this exact thing. Unix / Linux您可以使用
wordexp
进行此操作。 However, not that this has some security implications you should be aware of. 但是,这并不意味着您应该意识到一些安全隐患。 Namely it will expand shell variables and many if not all implementations of this results in a call to
sh
. 也就是说,它将扩展shell变量,并且如果不是全部,则许多实现将导致对
sh
的调用。
NOTE: It seems that OSX 10.9.5 leaks memory in wordexp
even after wordfree
is called. 注:似乎OSX 10.9.5泄漏内存
wordexp
即使wordfree
被调用。 See Is wordexp in libc on OSX 10.9.5 known to leak? 请参见是否知道OSX 10.9.5的libc中的wordexp泄漏? for details.
有关详细信息。
Windows I know this question was only tagged for Linux. Windows我知道这个问题仅针对Linux。 But someone else might be interested in a multiplatform solution.
但是其他人可能对多平台解决方案感兴趣。
Here you can use CommandLineToArgvW
. 在这里您可以使用
CommandLineToArgvW
。 Note that this is for wchar_t *
so the example code below first converts from char *
to wchar_t *
, does the split, and then converts back to char *
to get a consistent API for both platforms. 请注意,这是针对
wchar_t *
因此下面的示例代码首先将char *
转换为wchar_t *
,进行分割,然后再转换回char *
以获得两种平台的一致API。
After writing this implementation I also found __getmainargs
which supports char *
instead, but I have not tried using this. 编写
__getmainargs
此实现后,我还找到了__getmainargs
,它支持char *
,但是我没有尝试使用它。
Code example: 代码示例:
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;
}
*Make use of getopt ... For more information on getopt go through *使用getopt ... 有关 getopt的 更多信息,请通过 "man 3 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.