【问题标题】:Using execvp to execute command line arguments using full path name errors使用 execvp 使用完整路径名错误执行命令行参数
【发布时间】:2020-12-30 15:03:15
【问题描述】:

我对 Linux 还很陌生,所以请多多包涵。我正在尝试从终端执行命令行参数,每个参数都是可执行文件的完整路径。例如,这样的命令行:

./cmdarguments /Desktop/darren/lab01/c_ex1/a.out

这意味着cmdarguments 是我的父程序,下面的命令行是我希望执行的文件的路径,它只是打印出hello world

这是我目前的代码:

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

int main(int argc, char* argv[])
{
    int counter;
    
    for(counter = 0; counter < argc; counter++){
        
        pid_t pid = fork();
        if(pid < 0)
        {
            perror("Forking failed\n");
            exit(1);
        }
        else if(pid == 0)
        {
            char *args[] = {argv[counter], NULL};
            execvp(args[0], args);
            printf("Command completed.\n");
            exit(0);
        }

        
    }
    exit(0);
    
}

我知道我的代码中可能缺少很多内容,从我在网上阅读的内容来看,我只会让自己更加困惑。这是一项仅使用forkexec 的简单任务。现在,我当前的输出只是Command completed,而我用作第二个命令行参数的任何输出似乎都没有改变,它始终是Command completed

【问题讨论】:

  • counter = 0argv[0]./cmdarguments
  • 使用调试器。检查您传递给execvp 的参数 - 是您所期望的吗?
  • @KamilCuk 好的,所以我应该从 1 开始我的计数器,以便在第 0 个参数的父程序之后获取参数?
  • @kaylum 据我了解,execvp 的第一个参数是父程序,应该是第 0 个参数是吗?
  • 请注意,如果成功,execvp不会返回。所以printf("Command completed.\n"); 应该是perror("Command failed");。另外,不要在传递给perror 的字符串末尾添加\n,因为perror 将打印您的消息,后跟冒号、错误描述和换行符。

标签: c linux execvp


【解决方案1】:

关于你的程序的一些注意事项:

  1. exec* 系列函数不会在成功的情况下返回。这些函数将将您的整个过程替换为通过参数指定的新过程。这些函数仅在失败的情况下返回,并且可以从errno 或通过perror(打印errno 的描述)读取错误。可能的错误在the man page man execvp 中定义。您应该在exec*() 之后使用perror() 来打印错误。

    您的输出始终为Command completed,因为您的execvp() 调用始终失败。

  2. exec* 系列函数确实不需要需要了解“父”进程的任何信息(父进程实际上没有任何意义,因为它们替换了当前进程,无论它是父进程还是子进程任何事物)。唯一的参数是(取决于您使用的变体)新进程路径、它的参数和环境。

  3. 传递给 main 的 argv 参数将始终包含位置 0 的当前进程的名称,并且参数将紧随其后(直到 argc - 1)。

  4. perror() 函数接受一个字符串,然后打印它,后跟一个冒号、错误描述和一个换行符。你应该perror("x"),而不是perror("x\n")

  5. 如果出现故障并且您的程序无法继续,通常最好使用一个 不同于0 的数字退出,以向调用者(或者如果您是在 shell 中运行它)。

  6. main() 中使用exit() 是没有意义的,return 将具有相同的效果,因为它是主程序。如果您想从与main() 不同的函数中终止程序,exit() 函数很有用。

  7. 据我所知,/Desktop/darren/lab01/c_ex1/a.out 通常不是普通 UNIX 系统上的有效路径。您的主目录中通常有Desktop。您可能想使用~/Desktop/...$HOME/Desktop/.../home/yourname/Desktop/... 甚至是像./a.out 这样的相对路径。

如上所述,您的代码的正确版本是:

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

int main(int argc, char* argv[])
{
    unsigned counter;
    
    for(counter = 1; counter < argc; counter++) {
        pid_t pid = fork();
        if(pid < 0)
        {
            perror("fork failed");
            return 1;
        }
        else if(pid == 0)
        {
            char *args[] = {argv[counter], NULL};
            execvp(args[0], args);

            // OR, equivalent to the above two lines:
            // execlp(argv[counter], argv[counter], NULL);

            fprintf(stderr, "%s: ", argv[counter]);
            perror("execvp failed");
            return 1;
        }
    }

    return 0; 
}

示例输出:

$ ./cmdarguments ls pwd
cmdarguments x.c
/home/marco/test

$ ./cmdarguments /bin/ls /bin/pwd
cmdarguments x.c
/home/marco/test

$ ./cmdarguments /does/not/exist
/does/not/exist: execvp failed: No such file or directory

【讨论】:

    猜你喜欢
    • 2021-03-16
    • 2021-01-02
    • 1970-01-01
    • 2014-10-23
    • 2015-02-13
    • 2017-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多