【问题标题】:Why can't I see the results of execvp() on the command line?为什么我在命令行上看不到 execvp() 的结果?
【发布时间】:2015-12-17 08:05:53
【问题描述】:

请注意,这是一项家庭作业。目标是创建一个 shell 接口。

问题是为什么我在终端输入命令时看不到 execvp() 的结果?

代码如下:

int getcmd(char *prompt, char *args[], int *background)
{
     int length, i = 0;
     char *token, *loc;
     char *line;
     size_t linecap = 0;

     printf("%s", prompt);
     length = getline(&line, &linecap, stdin);



     if (length <= 0) {
       exit(-1);
     }

    // Check if background is specified..
    if ((loc = index(line, '&')) != NULL) {
       *background = 1;
       *loc = ' ';
    } else
       *background = 0;

while ((token = strsep(&line, " \t\n")) != NULL) {
     for (int j = 0; j < strlen(token); j++)
        if (token[j] <= 32)
            token[j] = '\0';
        if (strlen(token) > 0)
          args[i++] = token;
      }

   return i;
}

以下是我的主要功能:

int main()
{
    char *args[20];
    int bg;

    while(1){
        bg = 0;
        int cnt = getcmd("\n>>  ", args, &bg);
        pid_t child_pid = fork();
        //for (int i = 0; i < cnt; i++)
        // printf("\nArg[%d] = %s", i, args[i]);

        // a negative number will be returned only 
        // if the forking was unsuccessful i.e
        // no child process is cloned from the original
        // process
        if(child_pid < 0){
            fprintf(stderr, "Fork Failed");
            return 1;
         }

         // the return value for a successful fork of a child is 0
         else if(child_pid == 0){
             execvp(args[0], args);
         }

        // this is the parent process here
        else {
            int status;
            if (bg == 1){
                printf("\nBackground enabled..\n");
                getcmd("\n>>  ", args, &bg);
            }
            else{
                printf("\nBackground not enabled \n");
                waitpid(child_pid, NULL, 0);
            }
        }
    }   
 }

当我运行我的代码时,它会编译并给我提示符(>>)。当我运行诸如ls 之类的命令时,它只打印未启用背景(因为我没有指定&)。但是,如果我在另一个终端上执行ps 命令,我会看到有一个新进程正在运行。我忽略了什么吗?当我将 ls 作为参数提供给 execvp() 系统调用时,为什么我看不到它的结果?

【问题讨论】:

  • 是否 getcmd() NULL-terminate args?
  • 在调用execvp() 之后立即调用perror("exec failed"); exit(1); 可能会有所帮助。
  • Yes getcmd() null 终止并且 perror("exec failed") 返回:exec failed: Bad address
  • “地址错误”?什么时候做“ls”?真的吗?你在哪个平台上观察这个?
  • 是的.. Mac OSX(更具体地说:El Capitan)

标签: c macos process operating-system fork


【解决方案1】:

getcmd() 未初始化 line。它最初应该指向NULL:

char *line = NULL;

来自getline()'s man-page:

如果行 指向一个 NULL 指针,将分配一个新的缓冲区。


另外请问你在哪里NULL-终止args。 args 的元素在最后一个获得getcmd() 分配的值之后应该指向NULL。

您可以通过在开始时将所有args 元素初始化为NULL 来确保是这种情况

char * args[20];
for (size_t i = 0; i < 20; ++i)
{
  args[i] = NULL;
}

为了测试,可以像这样初始化args

char * args[] = {
  "ls",
  "ls",
  "-alrt",
  NULL /* a must */
}

来自execvp()s man-page:

execv()、execvp() 和 execvP() 函数提供指向以空字符结尾的字符串的指针数组 表示新程序可用的参数列表。第一个论点,按照惯例, 应该指向与正在执行的文件关联的文件名。指针数组必须是 由 NULL 指针终止。

【讨论】:

  • 不管我是否初始化行,它仍然给出同样的错误
  • 完美,现在可以使用了。我仍然不明白为什么你必须先将它们全部初始化为 NULL。
  • 不是全部,而是最后一个。 execve() 应该如何知道 argselement 中的哪一个指向有效内存。 @Ralphyabro 将所有设置为 NULL 只是一种懒惰的方式。顺便说一句,您的应用程序不适用于具有超过 17 个参数的命令。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-02
  • 1970-01-01
  • 1970-01-01
  • 2014-01-30
  • 1970-01-01
相关资源
最近更新 更多