繁体   English   中英

C执行一个命令,并用execvp输出另一个命令

[英]C executing a command with another commands output with execvp

我可以很好地执行“ 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 | | | | | | | head -1和ls的其他变体,但是当我做ls | sort -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);
    }
}
}

您想做ls | sort事情ls | sort ls | sort但你的行为方式像

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

将不起作用,因为在这里您在ls上调用execvp并进行sort ,这是两个单独的进程而不是单个进程。

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

要实现上述目的,可以通过调用fork()创建两个进程,并使用exec()系列函数替换ls并在子进程和父进程中进行sort

这是示例代码

int main(void) {
        int p[2];
        pipe(p);
        char *arg[] = {"ls","sort",NULL};
        if(fork()==0) {
                close(0);/* close the stdin stream so that this 
process shoulbn't read from stdin */
                dup(p[0]);/* read from read end of pipe */
                close(p[1]);
                execlp(arg[1],arg[1],(char*)NULL);
        }
        else{
                close(1);/* close the stdout stream, so that o/p shouldn't print on monitor */
                dup(p[1]); /*  stdout result redrecting to write end of pipe */
                close(p[0]);
                execlp(arg[0],arg[0],(char*)NULL);
        }
        return 0;
}

| 是外壳功能。 您需要做与外壳程序相同的操作,即使用pipeforkdup2execvp创建一个管道,生成一个新进程,并将该管道分别连接到进程的stdin和stdout。

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

记住关闭不需要的管端! 即在生产者过程中, close(link[0]) ; 在使用者进程中, close(link[1]) 如果您忘记了这一部分,事情可能会“卡住”(命令似乎永远挂着)。

当然,如果你希望你的原来的程序继续下去,你需要用另一种内部的代码fork (和waitpid为它)。


execString ,如果命令输出大量数据,则execString会损坏。 在某个时候,管道将充满,命令将暂停,等待另一个进程将管道排空(通过读取管道)。 您的程序将停留在wait ,等待命令终止。 结果是死锁。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM