簡體   English   中英

C拆分CMD參數

[英]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字符串拆分為argcargv傳遞給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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM