简体   繁体   English

C拆分CMD参数

[英]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字符串拆分为argcargv传递给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程序特有的,因此需要对单个命令进行修改。

Splitting a command line 分割命令行

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.

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