【问题标题】:Execv not working when using bin/time使用 bin/time 时 Execv 不起作用
【发布时间】:2017-04-19 02:48:49
【问题描述】:

当我尝试执行/bin/time /bin/echo Hello world 时,我的程序出现问题,我没有得到任何输出。我知道这个示例代码有效 例如 /bin/date 或 /bin/echo ,我认为它也应该与时间一起工作,但它不是

int main(int argc, char * argv []) {    
    int err = 1;
    char *array[3] = {"/bin/time", "/bin/echo", "Hello World"};
    pid_t childPIorZero = fork();

    if (childPIorZero < 0){
        perror("fork() error");
        exit(-1);                        
    }
    if (childPIorZero != 0){
        printf("I'm the parent %d, my child %d\n",getpid(),childPIorZero);
        wait(NULL); 
    }           
    else{
         printf("I'm the child %d, my parent %d\n",getpid(), getppid());
         err = execv(array[0], array);
         printf("error = %d\n", err);
         printf("%s\n", strerror(err));
    }

    return 0;
}

我虽然问题是我以错误的方式将参数传递给 execv,但它适用于 echo bin 和 date bin,所以我不知道出了什么问题。输出如下:

I'm the parent 28001, my child 28011
I'm the child 28011, my parent 28001
error = -1
Unknown error -1

【问题讨论】:

  • array 末尾需要一个空指针:char *array[] = { "/bin/time", "/bin/echo", "Hello World", 0 };。否则,execv() 不知道参数列表何时结束 - 或者它在遇到空指针时结束,这可能不会有一段时间,天知道你得到了什么垃圾。
  • 但是,这不一定是您的直接问题。你确定你有一个/bin/time 而不是/usr/bin/time?从execv() 捕获返回值没有任何好处;如果返回,则失败。要传递给strerror() 的值应该是errno;这不是来自execv() 的返回状态,因为所有错误编号都是正数。如果execv() 失败,则以非零(失败)状态退出也是一个好主意。并且错误消息应该打印到stderr,而不是stdout
  • 谢谢,@JonathanLeffler 我尝试使用 null 完成,但它不起作用,正如我所说我已经尝试使用 /bin/echo 并且它有效,所以我认为它应该有效。我也尝试将路径更改为/usr/bin/time,但也没有用
  • 谢谢,@JonathanLeffler 我设法让它工作,但我不知道为什么我必须像这样指定时间目录/usr/bin/time/ 而回声只有在我这样写时才有效这个/bin/echo,如果我这样做/usr/bin/echo,我会得到一个错误。这很奇怪,因为我去了 dir /bin/ 并执行了 echo 并且它起作用了,但是在那之后我做了 ls 并且我在 dir 列表中找不到 echo,这是我的操作系统的问题吗?
  • 我对@9​​87654342@ 上的斜杠没有现成的解释。如果你有/bin/echo,你可能没有/usr/bin/echo(尽管因为/bin/usr/bin之一是Solaris上另一个的符号链接,你可能没有在那里运行,但如果你是,你没有那个问题)。 echo 命令是一个内置的 shell,但也是一个单独的可执行文件。你在哪个平台?在 macOS Sierra 上,有 /usr/bin/time,但没有 /bin/time。 Linux(Ubuntu 16.04 LTS)似乎也是如此。尝试删除尾部斜杠。

标签: c fork exec execv


【解决方案1】:

此代码在运行 macOS Sierra 10.12.4 的 Mac 上托管的 Ubuntu 16.04 LTS VM 上运行正常(在 macOS 上也运行正常)。

#define _XOPEN_SOURCE 700
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    char *array[] = { "/usr/bin/time", "/bin/echo", "Hello World", 0 };
    pid_t childPIorZero = fork();

    if (childPIorZero < 0)
    {
        perror("fork() error");
        exit(-1);
    }
    if (childPIorZero != 0)
    {
        printf("I'm the parent %d, my child %d\n", getpid(), childPIorZero);
        int status;
        int corpse;
        while ((corpse = wait(&status)) != -1)
            printf("PID %d exited with status 0x%.4X\n", corpse, status);
    }
    else
    {
        printf("I'm the child %d, my parent %d\n", getpid(), getppid());
        execv(array[0], array);
        int errnum = errno;
        fprintf(stderr, "(%d) %s\n", errnum, strerror(errnum));
        exit(1);
    }

    return 0;
}

问题中代码的主要更改包括:

  • 更改time 可执行文件的位置。
  • 将空指针添加到array 的末尾。
  • execv() 失败后报告stderr 上的错误,而不是stdout
  • 报告来自errno 的错误,而不是来自execv() 的返回值,如果它返回,则始终是-1
  • 如果execv() 失败,则会以错误状态退出。
  • 循环直到没有子进程(在有趣的情况下,进程可以继承同一进程的前一个化身派生的子进程 - 大多数情况下,您不必担心,但我总是使用循环等待)。
  • 报告孩子的退出状态。

在 Ubuntu 上,我使用以下代码编译:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
>     -Wstrict-prototypes -Wold-style-definition ev11.c -o ev11
$ ./ev11
I'm the parent 25129, my child 25130
I'm the child 25130, my parent 25129
Hello World
0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 1620maxresident)k
8inputs+0outputs (1major+66minor)pagefaults 0swaps
PID 25130 exited with status 0x0000
$

我在 macOS 上使用了相同的编译命令行(当然是不同的编译器)并得到:

$ ./ev11
I'm the parent 3220, my child 3221
I'm the child 3221, my parent 3220
Hello World
        0.00 real         0.00 user         0.00 sys
PID 3221 exited with status 0x0000
$

【讨论】:

    猜你喜欢
    • 2019-02-14
    • 2017-05-17
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 2016-08-25
    • 1970-01-01
    • 2018-03-28
    相关资源
    最近更新 更多