8

我正在尝试将用户输入的参数传递给execvp().

到目前为止,我已经拆分了字符串。如果用户键入ls -a,temp则保存为 "ls" 和 "-a" 后跟一个 NULL 字符。我不太确定如何在execvp. 在示例中,我已经看到它使用execvp(temp[position], temp). 我知道我现在尝试做的方式是错误的,但我不确定如何正确地做!目前我遇到了分段错误。

int main(int argc, char *argv[]) 
{
    char line[124];
    int size = 124;
    char *temp = NULL;

    while(fgets(line, size, stdin) != NULL ) {
        if (strcmp(line, "exit\n") == 0) {
            exit(EXIT_SUCCESS);
        }
        temp = strtok(line, " ");
        while (temp != NULL) {
            printf("%s\n", temp);
            temp = strtok(NULL, " ");
        }
        execvp(temp, &temp);    
    }
    return EXIT_SUCCESS;
}
4

3 回答 3

7

您的问题是这temp是一个单指针,您需要将一组指针传递给execvp().

就像是:

    enum { MAX_ARGS = 64 };
    char *args[MAX_ARGS];
    char **next = args;

    temp = strtok(line, " ");
    while (temp != NULL)
    {
        *next++ = temp;
        printf("%s\n", temp);
        temp = strtok(NULL, " ");
    }
    *next = NULL;
    execvp(args[0], args);

请注意,参数列表已被赋予一个空指针作为终止符,就像argv[argc] == NULLin一样main()。显然,我忽略了错误检查(如果传递的参数超过 63 个,就会溢出args数组)。但这包含了核心思想。


在这个例子中,我似乎无法获得简单的命令ls来工作,我已经尝试过mkdir并且echo它们似乎工作正常。传递ls返回 -1 从execvp().

我不确定问题可能是什么——所有这些都对我有用:

  • ls
  • ls -l
  • ls -l madump.cmadump.c恰好是我正在测试的目录中的文件)

我使用的代码是:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void) 
{
    char line[1024];

    while (fgets(line, sizeof(line), stdin) != NULL)
    {
        if (strcmp(line, "exit\n") == 0)
            exit(EXIT_SUCCESS);

        char *args[64];
        char **next = args;
        char *temp = strtok(line, " \n");
        while (temp != NULL)
        {
            *next++ = temp;
            printf("%s\n", temp);
            temp = strtok(NULL, " \n");
        }
        *next = NULL;

        puts("Checking:");
        for (next = args; *next != 0; next++)
            puts(*next);

        execvp(args[0], args);
    }

    return EXIT_SUCCESS;
}

请注意,在创建一个名称末尾带有换行符的目录之后,我将其添加\n到了令牌列表中。strtok()适合烦人的朋友和困惑的半受过教育的敌人,但从大多数其他角度来看却是一种滋扰。execvp()请注意我是如何在实际这样做之前打印出将要传递给的数据的。通常,我会使用printf("<<%s>>\n", *next);而不是仅仅puts()为了获得参数开始和结束的明确指示。

运行命令 ( doit) 的输出是:

$ ./doit
ls -l madump.c
ls
-l
madump.c
Checking:
ls
-l
madump.c
-rw-r--r--  1 jleffler  staff  2352 Jul 28  2011 madump.c
$

你从你的版本中得到了什么?

于 2013-03-21T05:04:20.893 回答
3

正如您的代码目前看起来一样,在您while(temp != NULL)完成后,temp将为 NULL!

execvp期望第一个参数是作为新进程映像的文件的路径。第二参数应该是一个以 NULL 结尾的字符串数组,其中该数组的最后一个成员是 NULL 指针,第一个成员是第一个参数中指定的文件的文件名。

要在您的代码中实现这一点,请考虑以下while循环:

char **argList = NULL;
unsigned int numArgs = 0;
while (temp != NULL) {
    numArgs++;

    /* Reallocate space for your argument list */
    argList = realloc(argList, numArgs * sizeof(*argList));

    /* Copy the current argument */
    argList[numArgs - 1] = malloc(strlen(temp) + 1, 1); /* The +1 for length is for the terminating '\0' character */
    snprintf(argList[numArgs - 1], strlen(temp) + 1, "%s", temp);

    printf("%s\n", temp);
    temp = strtok(NULL, " ");
}

/* Store the last NULL pointer */
numArgs++;
argList = realloc(argList, numArgs * sizeof(*argList));
argList[numArgs - 1] = NULL;

/* Finally, pass this to execvp */
execvp(argList[0], argList);
/* If you reach here, execvp() failed */

我上面提供的代码并没有做一些错误检查(比如何时reallocmalloc失败),但基本上记住了这几点:

  1. 参数 1:要放入内存的文件的路径名。
  2. 参数 2:参数列表,其中该列表的第一个成员 = 文件名,最后一个成员 = NULL 指针。

请查看文档以获得更好的清晰度和一个非常简单的示例。

于 2013-03-21T04:57:08.023 回答
1

我猜测段错误是因为您将 NULL 指针传递给 execvp。调用上方的循环确保了这一点。

要执行您想要执行的操作,您需要为当前调用的内容创建一个字符串指针数组temp。这将成为argv您调用的程序的数组。这就是为什么该命令通常用作execvp (temp[0], temp)-argv[0]通常是程序的名称。

所以尝试创建一个字符串指针数组,并让每个指针指向一个来自line. 您可能需要使用 malloc,但如果您想聪明一点,您可以直接指向line. 如果这样做,则需要在每个“单词”之后立即将字符设置为\0.

于 2013-03-21T04:56:44.490 回答