如何正确地将管道中先前程序的输出发送到下一个程序?

时间:2017-12-11 21:35:29

标签: c unix

  

目标是实施终端命令 prog1>文件&& prog2 | prog3 给出参数prog1fileprog2prog3

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
    int fd,status,pipefd[2];
    pipe(pipefd);
    /* S_IRWXU - full acces to file */
    fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
if (!fork()){
    dup2(fd, 1); /* redirection to file */
    close(fd); /* it's useless now */
    execlp(argv[1], argv[1], NULL);
}
else {
    wait(&status);
    if (!status){
        if (fork()){
            dup2(pipefd[1],1);
            close(pipefd[1]);
            close(pipefd[0]);
            execlp(argv[3], argv[3],NULL);
        }
    wait(NULL);
    dup2(pipefd[0],0);
    close(pipefd[0]);
    close(pipefd[1]);
    execlp(argv[4], argv[4],NULL);  
    }
}
return 0;
}

我无法使此代码显示上一个程序从上一个程序获得的数据。 例如(假设程序的名称为prog):

./prog ps f date echo

不显示当前日期。我不明白为什么。你能解释一下吗?

2 个答案:

答案 0 :(得分:2)

如果你跑:

date | echo

在shell的命令行提示符下,您将获得换行符并且没有日期。将echo更改为cat,您会看到日期:

$ date | echo

$ date | cat
Mon Dec 11 16:35:54 PST 2017
$

您可以修复代码,以便更好地处理错误:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
    if (argc != 5)
    {
        fprintf(stderr, "Usage: %s prog1 file prog2 prog3\n", argv[0]);
        return 1;
    }
    int pid = fork();
    if (pid < 0)
    {
        fprintf(stderr, "%s: failed to fork\n", argv[0]);
        return 1;
    }
    else if (pid == 0)
    {
        /* S_IRWXU - full access to file */
        int fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
        if (fd < 0)
        {
            fprintf(stderr, "%s: failed to open file %s for writing\n", argv[0], argv[2]);
            return 1;
        }
        dup2(fd, 1); /* redirection to file */
        close(fd);   /* it's not needed now */
        execlp(argv[1], argv[1], NULL);
        fprintf(stderr, "%s: failed to execute %s\n", argv[0], argv[1]);
        return 1;
    }
    else
    {
        int status;
        wait(&status);
        if (status == 0)
        {
            int pipefd[2];
            pipe(pipefd);       // Error check?
            pid = fork();
            if (pid < 0)
            {
                fprintf(stderr, "%s: failed to fork\n", argv[0]);
                return 1;
            }
            else if (pid == 0)
            {
                dup2(pipefd[1], 1);
                close(pipefd[1]);
                close(pipefd[0]);
                execlp(argv[3], argv[3], NULL);
                fprintf(stderr, "%s: failed to execute %s\n", argv[0], argv[3]);
                return 1;
            }
            else
            {
                dup2(pipefd[0], 0);
                close(pipefd[0]);
                close(pipefd[1]);
                execlp(argv[4], argv[4], NULL);
                fprintf(stderr, "%s: failed to execute %s\n", argv[0], argv[4]);
                return 1;
            }
        }
    }
    return 0;
}

很多C编程都是关于错误处理的。拥有一个使错误报告更简单的函数库有很大帮助。例如,我有一个包含头文件stderr.h的库和stderr.c中的实现 - 来自GitHub的源代码。它简化(并改进了)错误报告:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "stderr.h"

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);
    if (argc != 5)
        err_usage("prog1 file prog2 prog3");
    int pid = fork();
    if (pid < 0)
        err_syserr("failed to fork: ");
    else if (pid == 0)
    {
        /* S_IRWXU - full access to file */
        int fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
        if (fd < 0)
            err_syserr("failed to open file %s for writing: ", argv[2]);
        dup2(fd, 1); /* redirection to file */
        close(fd);   /* it's not needed now */
        execlp(argv[1], argv[1], NULL);
        err_syserr("failed to execute %s: ", argv[1]);
    }
    else
    {
        int status;
        wait(&status);
        if (status == 0)
        {
            int pipefd[2];
            pipe(pipefd);       // Error check?
            pid = fork();
            if (pid < 0)
                err_syserr("failed to fork");
            else if (pid == 0)
            {
                dup2(pipefd[1], 1);
                close(pipefd[1]);
                close(pipefd[0]);
                execlp(argv[3], argv[3], NULL);
                err_syserr("failed to execute %s: ", argv[3]);
            }
            else
            {
                dup2(pipefd[0], 0);
                close(pipefd[0]);
                close(pipefd[1]);
                execlp(argv[4], argv[4], NULL);
                err_syserr("failed to execute %s: ", argv[4]);
            }
        }
    }
    return 0;
}

例如,err_syserr()函数报告系统错误号和消息以及命令名称(prog41)和呼叫中指定的消息。 (是的,有一些方法可以再压缩两个程序 - 可以删除外部else块上的if,使下面的代码减少一级(并且代码三行更短) ,例如。)

此程序为prog41,测试输出可能为:

$ ./prog41 rigmarole /dev/not-there fudge pumpkin
prog41: failed to open file /dev/not-there for writing: error (1) Operation not permitted
$ ./prog41 rigmarole not-there fudge pumpkin
prog41: failed to execute rigmarole: error (2) No such file or directory
$ ./prog41 ps not-there fudge pumpkin
prog41: failed to execute pumpkin: error (2) No such file or directory
prog41: failed to execute fudge: error (2) No such file or directory
$ ./prog41 ps not-there date pumpkin
prog41: failed to execute pumpkin: error (2) No such file or directory
$ ./prog41 ps not-there date cat
Mon Dec 11 16:49:11 PST 2017
$ ./prog41 proxy mangler
Usage: prog41 prog1 file prog2 prog3
$

成功运行程序后,文件not-there当然在那里。

答案 1 :(得分:-1)

你有三个执行官,但有2个叉子。我个人会做三个叉子(每个exec一个),并有2个管道在流程中进行通信。