C使用execvp

时间:2018-05-31 16:41:12

标签: c unix pipe

我很好地执行像“ls”之类的命令和类似的东西,但我想做类似“ls | sort”的操作,但是execvp系统调用不支持“|”。如何仅使用系统调用来执行此操作?当我尝试像

这样的东西时
char *arg[] = {"ls","|","sort",NULL};
execvp(arg[0],arg);

它不起作用,我该怎么做?

编辑:

char* execString (char string[]){
int link[2];
pipe(link);

if (fork() == 0){
    int i = 0;
    char *p = strtok(string," ");
    char *x[spacecount(string)+2];

    while(p){
        x[i++] = p;
        p = strtok(NULL," ");
    }
    x[i] = NULL;

    dup2(link[1],1);
    close(link[0]);
    close(link[0]);

    execvp(x[0],x);
    _exit(0);
} else {
    wait(NULL);
    close(link[1]);
    char buf[512];
    int i = 0;

    while (read(link[0],&buf[i++],1) == 1);

    close(link[0]);
    buf[i-2] = '\0';

    return strdup(buf); 
    }
}

这是我执行的函数,用于执行包含命令的字符串,其返回值是指向包含该命令输出的字符串的指针,如何将该输出用作新命令的输入使用execvp或exec系列中的其他函数?

Edit2:所以我创建了一个新函数,接收两个字符串作为参数并执行第一个,然后第二个使用第一个exec的输出作为输入,我认为它工作正常它与ls |头-1和ls的其他变化,但当我做ls |的事情排序-R它不起作用,我尝试了几件事我无法理解为什么会这样,这里是代码:

char* execStrings (char previousstring[], char string[]){
int link[2];
pipe(link);

if (fork() == 0){
    int i = 0;
    char *previouscommand[spacecount(previousstring)+2];
    char *temp = strtok(previousstring," ");
    while(temp){
        previouscommand[i++] = temp;
        temp = strtok(NULL," ");
    }
    previouscommand[i] = NULL;

    dup2(link[1],1); /*  stdout result redrecting to write end of pipe */
    close(link[1]);
    close(link[0]);
    execvp(previouscommand[0],previouscommand);

} else {
    wait(NULL);
    int res[2];
    pipe(res);

    if(fork() == 0){
        int i = 0;
        char *temp = strtok(string," ");
        char *command[spacecount(string)+2];

        while(temp){
            command[i++] = temp;
            temp = strtok(NULL," "); 
        }
        command[i] = NULL;

        dup2(link[0],0);
        close(link[0]);
        close(link[1]);

        dup2(res[1],1);
        close(res[1]);
        close(res[0]);

        execvp(command[0],command)
    } else {
        wait(NULL);

        close(res[1]);
        char buf[512];
        int i = 0;

        while (read(res[0],&buf[i++],1) == 1);

        close(res[0]);
        buf[i-2] = '\0';

        return strdup(buf);
    }
}
}

2 个答案:

答案 0 :(得分:2)

你想做ls | sort之类的事情,但是你想做的事情

char *arg[] = {"ls","|","sort",NULL};
execvp(arg[0],arg); /*it won't work */

无法工作,因为您在execvpls拨打sort,这是两个独立的流程而不是单个流程。还

ls     |    sort  => output of process-1 make as input to process-2 & execute it   
|            |
process-1  process-2

要实现上述目标,请致电fork()并使用exec()系列函数替换子级&{父母过程。

这是示例代码

ls

答案 1 :(得分:1)

|是一个shell功能。您需要执行shell所做的相同操作,即使用pipeforkdup2execvp来创建管道,生成新进程并连接管道进程' stdin和stdout分别。

execString函数中获取代码,但替换else块。在父流程中,您应该dup2(link[0], 0)(将管道的读取端连接到stdin),然后execvp其他程序(例如sort)。

请记住关闭您不需要的管道末端!即在制片人过程中,close(link[0]);在消费者流程中,close(link[1])。如果你忘了这一部分,事情就会陷入困境。 (命令看似永远悬挂)。

当然,如果您希望原始程序继续运行,您需要将该代码包含在另一个fork(以及waitpid)中。

另外,如果命令输出大量数据,则execString会被破坏。在某些时候,管道将变满并且命令将暂停,等待另一个过程排空管道(通过读取它)。您的程序将卡在wait中,等待命令终止。结果是死锁。

要解决此问题,请在完成从管道中读取后调用wait