Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 通过父级执行命令时使用管道_C_Linux_Pipe - Fatal编程技术网

C 通过父级执行命令时使用管道

C 通过父级执行命令时使用管道,c,linux,pipe,C,Linux,Pipe,我要实现一个无名管道,我必须在父进程中执行命令,而不是在他的任何子进程中。每个“-”都等于对管道(“|”)的调用,也是赋值的一部分 我有这个密码。有人能给我解释一下为什么它不起作用吗 #include <stdio.h> #include <dirent.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> // for open flags #includ

我要实现一个无名管道,我必须在父进程中执行命令,而不是在他的任何子进程中。每个“-”都等于对管道(“|”)的调用,也是赋值的一部分 我有这个密码。有人能给我解释一下为什么它不起作用吗

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h> // for open flags
#include <time.h> // for time measurement
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

void my_exec(char* cmd, char** argv)
{
    int pipefd[2], f;

    if (pipe(pipefd) < 0)
        perror("pipe creation failed");

    f = fork();
    assert(f >= 0);

    if (f == 0) {
        // inside son process - connecting STDOUT to pipe write
      if (dup2(pipefd[1], STDOUT_FILENO) < 0)
            perror("dup2 failed");

        close(pipefd[0]);
        close((int)stdout);


    } else {
        // inside parent process - connecting STDIN to pipe read  and execute command with args
      if (dup2(pipefd[0], STDIN_FILENO) < 0)
            perror("dup2 failed");

        close(pipefd[1]);
       close((int)stdin);



if (execvp(cmd, argv) < 0)
                perror("execvp failed");
        }

}

int main(int argc, char** argv)
{
    assert(strcmp(argv[argc-1], "-"));

    int i;
    for (i = 1; i < argc; ++i) {
        if (!strcmp(argv[i], "-")) {
            argv[i] = NULL;
            my_exec(argv[1], &argv[1]);
            argv = &argv[i];
            argc -= i;
            i = 0;
        }
    }

    char* args[argc];
    args[argc-1] = NULL;

    for (i = 1; i < argc; ++i) {
        args[i-1] = argv[i];
    }

    if (execvp(args[0], args) == -1)
        perror("execvp failed");
    return;
}
返回

total 24
-rw-rw-r-- 1 omer omer 1463 May 23 19:38 mypipe.c
-rwxrwxr-x 1 omer omer 7563 May 23 19:37 mypipe.o
-rw-rw-rw- 1 omer omer  873 May 23 20:01 nice.c
-rwxrwxr-x 1 omer omer 7417 May 23 19:44 nice.o
-rw-rw-r-- 1 omer omer    0 May 23 17:10 try
这显然意味着管道不工作。。。有什么想法吗


我需要确保每次对np_exec的调用都会启动一个子进程,该子进程将继续解析其余的参数,而原始父进程将执行给定的程序和参数(使用execvp)

编辑: 我想我发现了错误: 我切换管道的“读写”端

正确的功能:

void np_exec(char* cmd, char** argv)
{
    int pipefd[2];
    int file;

    if (pipe(pipefd) < 0)
        perror("failed to create pipe");

    file = fork();
    assert(file >= 0);

    if (file != 0) {
        // inside parent process - connecting STDOUT to pipe write and execute command with args
      if (dup2(pipefd[WRITE], STDOUT_FILENO) < 0)
            perror("the function dup2 failed");

        close(pipefd[READ]);
        close((int)stdout);

        if (execvp(cmd, argv) < 0)
            perror("the function execvp failed");

    } else {
        // inside son process - connecting STDIN to pipe read
      if (dup2(pipefd[READ], STDIN_FILENO) < 0)
            perror("the function dup2 failed");

        close(pipefd[WRITE]);
       close((int)stdin);
    }

}
void np_exec(char*cmd,char**argv)
{
int-pipefd[2];
int文件;
如果(管道(管道FD)<0)
perror(“未能创建管道”);
file=fork();
断言(文件>=0);
如果(文件!=0){
//在父进程内部-使用args将STDOUT连接到管道写入和执行命令
if(dup2(pipefd[WRITE],标准输出文件号)<0)
perror(“函数dup2失败”);
关闭(pipefd[READ]);
关闭((int)标准输出);
if(execvp(cmd,argv)<0)
perror(“函数execvp失败”);
}否则{
//内部子进程-将标准DIN连接到管道读取
如果(dup2(pipefd[READ],标准文件号)<0)
perror(“函数dup2失败”);
关闭(pipefd[WRITE]);
关闭((int)stdin);
}
}

更新:所以,原来我原来的答案太离谱了。直到现在我才完全明白你想做什么

您的代码基本上是正确的。它不起作用的原因很简单:Shell假设启动它的进程完成时命令就完成了

请允许我举例说明。假设您运行
/mypipea-b-c

下面是引擎盖下发生的事情:

  • shell派生一个进程来执行
    mypipe
    。这是程序开始执行的时间

  • 您的程序分叉,父程序调用
    exec(a)
    。该子级继续解析其他参数并处理管道创建,正如它所期望的那样

现在,在这一点上,您有一个父进程运行程序
a
,在shell看来,它是与命令
/mypipe
相对应的进程,您有一个子进程,shell完全忽略了它,执行
mypipe
设置管道的任务,读取要执行的其余程序等

所以,现在你有了一个比赛条件。由于
mypipe
后面的进程已被程序
a
替换,因此只要
a
终止,shell就会假定您键入的命令已完成(即假定
mypipe
已完成),并打印提示,希望您键入下一个命令

问题是:
a
会很快终止,而您的子进程仍在查看其他程序列表,设置管道,重定向输入和输出,等等。例如,子进程可能仍在创建管道和解析其他程序,而此时
a
已经完成并将所有内容写入stdout-Oops

你怎么解决这个问题?简单:颠倒命令执行的顺序。首先执行最后一个命令,然后执行倒数第二个命令,等等。为什么?因为如果这样做,父级将是管道上的最后一个,因此它会阻止等待输入到达管道读取通道。当父级终止时,意味着管道中的最后一个命令已经终止,这正是我们想要的。没有竞争条件,shell也不会被欺骗,以为我们的命令已经完成,而实际上没有

所以,这就是从右到左而不是从左到右解析程序列表的问题。另外,如果您这样做,您将不再需要辅助
args
数组,这非常好

以下是经过测试和运行的代码:

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h> // for open flags
#include <time.h> // for time measurement
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

void my_exec(char* cmd, char** argv)
{
    int pipefd[2], f;

    if (pipe(pipefd) < 0)
        perror("pipe creation failed");

    f = fork();
    assert(f >= 0);

    if (f == 0) {
        if (dup2(pipefd[1], STDOUT_FILENO) < 0)
            perror("dup2 failed");

        close(pipefd[0]);

    } else {
        if (dup2(pipefd[0], STDIN_FILENO) < 0)
            perror("dup2 failed");

        close(pipefd[1]);

        if (execvp(cmd, argv) < 0)
            perror("execvp failed");
        }
}

int main(int argc, char** argv)
{
    assert(strcmp(argv[argc-1], "-"));

    int i;
    for (i = argc-1; i >= 1; i--) {
        if (!strcmp(argv[i], "-")) {
            argv[i] = NULL;
            my_exec(argv[i+1], &argv[i+1]);
            argc = i;
        }
    }

    if (execvp(argv[0], &argv[1]) == -1)
        perror("execvp failed");

    return 0;
}
#包括
#包括
#包括
#包括
#包括//打开标志
#包括//用于时间测量
#包括
#包括
#包括
#包括
#包括
作废我的执行代码(char*cmd,char**argv)
{
int-pipefd[2],f;
如果(管道(管道FD)<0)
perror(“管道创建失败”);
f=fork();
断言(f>=0);
如果(f==0){
if(dup2(pipefd[1],标准输出文件号)<0)
perror(“dup2失败”);
关闭(pipefd[0]);
}否则{
如果(dup2(pipefd[0],标准文件号)<0)
perror(“dup2失败”);
关闭(pipefd[1]);
if(execvp(cmd,argv)<0)
perror(“execvp失败”);
}
}
int main(int argc,字符**argv)
{
断言(strcmp(argv[argc-1],“-”);
int i;
对于(i=argc-1;i>=1;i--){
如果(!strcmp(argv[i],“-”)){
argv[i]=NULL;
我的执行官(argv[i+1],&argv[i+1]);
argc=i;
}
}
if(execvp(argv[0],&argv[1])=-1)
perror(“execvp失败”);
返回0;
}

Wait,您希望在父进程中执行哪个命令,在子进程中执行哪个命令?我需要确保每次调用np_exec都会启动一个子进程,继续解析其余参数,而原始父进程则执行给定的程序和参数(使用execvp),“当原始父进程执行给定的程序和参数时(使用execvp)”我认为这没有意义:如果父进程调用execvp,它将被execvp最终调用的任何函数所替换。是的,但我希望子进程继续执行下一个参数,而父进程执行当前命令。(如果我错了,请纠正我,在家长使用execvp后,过程结束了吗?)感谢您的回答。将exec命令放在孩子中确实更有意义。但是,在这个任务中,我被迫使用execv
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h> // for open flags
#include <time.h> // for time measurement
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

void my_exec(char* cmd, char** argv)
{
    int pipefd[2], f;

    if (pipe(pipefd) < 0)
        perror("pipe creation failed");

    f = fork();
    assert(f >= 0);

    if (f == 0) {
        if (dup2(pipefd[1], STDOUT_FILENO) < 0)
            perror("dup2 failed");

        close(pipefd[0]);

    } else {
        if (dup2(pipefd[0], STDIN_FILENO) < 0)
            perror("dup2 failed");

        close(pipefd[1]);

        if (execvp(cmd, argv) < 0)
            perror("execvp failed");
        }
}

int main(int argc, char** argv)
{
    assert(strcmp(argv[argc-1], "-"));

    int i;
    for (i = argc-1; i >= 1; i--) {
        if (!strcmp(argv[i], "-")) {
            argv[i] = NULL;
            my_exec(argv[i+1], &argv[i+1]);
            argc = i;
        }
    }

    if (execvp(argv[0], &argv[1]) == -1)
        perror("execvp failed");

    return 0;
}