如何运行另一个程序,通过stdin传递数据,并在Linux中获取其stdout输出?

时间:2017-11-30 17:17:35

标签: c linux pipe

基本上我想在C:中实现这样的目标 output=$(echo -n 1234 | md5sum)
1234是输入,md5sum是我想要运行的程序。

我已经检查了一些SO问题,但似乎没有一个正是我正在寻找的,或者它们没有提供我可以测试的完整代码示例。

我已经尝试popen并能够读取或写入其他程序,但显然它不是双向的。

有些帖子似乎建议pipe使用dup2或其他一些功能,但他们没有解释如何让它们正常工作。

2 个答案:

答案 0 :(得分:1)

D3可以使用

主要问题是它想要实现相当于shell命令:

popen()

并且 可以用C popen()编写:

output=$(echo -n 1234 | md5sum)

这个输出是:

#include <stdio.h>

int main(void)
{
    char output[64];
    FILE *fp = popen("echo -n 1234 | md5sum", "r");
    if (fp == 0)
    {
        fprintf(stderr, "failed to create pipeline\n");
        return 1;
    }
    size_t nbytes = fread(output, sizeof(char), sizeof(output), fp);
    pclose(fp);
    if (nbytes > 0)
    {
        printf("output=[%.*s]\n", (int)nbytes, output);
        return 0;
    }
    else
    {
        printf("no output available!\n");
        return 1;
    }
}

请注意,这相当于以下第一个命令的输出:

output=[4c35fa2227e11ba8c892cbbb5d46417c  -
]

(使用$ printf "%s %s\n" -n 1234 | md5sum 4c35fa2227e11ba8c892cbbb5d46417c - $ printf "%s" 1234 | md5sum 81dc9bdb52d04dc20036dbd8313ed055 - $ 并非完全可移植。有空间认为您期望第二个命令的输出。)

如果您想要双向沟通

但是,标题中的标题问题表明您希望程序将数据写入echo -n命令并再次读取响应哈希值。这当然是可行的,但你必须更加努力,md5sum不再合适。我懒得不使用我首选的错误报告功能,这些功能在SOQ — Stack Overflow Questions存储库的GitHub上可用作LibSOQ目录中的文件popen()stderr.c 。当你只是编写测试并在测试指示失败时进行函数调用时,它使错误检查变得更加简单。

stderr.h

示例输出(程序为#include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include "stderr.h" static void fd_copy(int ifd, int ofd) { char buffer[1024]; ssize_t rbytes; while ((rbytes = read(ifd, buffer, sizeof(buffer))) > 0) { ssize_t wbytes; if ((wbytes = write(ofd,buffer, (size_t)rbytes)) != rbytes) err_syserr("short write %zd bytes instead of %zd expected: ", wbytes, rbytes); } } static void be_childish(int *to_child, int *to_parent) { if (dup2(to_child[0], STDIN_FILENO) != STDIN_FILENO) err_syserr("failed to duplicate pipe to standard input: "); if (dup2(to_parent[1], STDOUT_FILENO) != STDOUT_FILENO) err_syserr("failed to duplicate pipe to standard output: "); close(to_child[1]); close(to_child[1]); close(to_parent[0]); close(to_parent[0]); char *cmd[] = { "md5sum", 0 }; execvp(cmd[0], cmd); err_syserr("failed to execute command %s: ", cmd[0]); /*NOTREACHED*/ } static void be_parental(const char *fname, int *to_child, int *to_parent) { close(to_child[0]); close(to_parent[1]); int fd = open(fname, O_RDONLY); if (fd < 0) err_syserr("failed to open file '%s' for reading: ", fname); fd_copy(fd, to_child[1]); close(fd); close(to_child[1]); char buffer[128]; ssize_t rbytes = read(to_parent[0], buffer, sizeof(buffer)); close(to_parent[0]); if (rbytes <= 0) err_syserr("read error (or unexpected EOF) from hash process: "); buffer[strspn(buffer, "0123456789abcdefABCDEF")] = '\0'; printf("%s: MD5 %s\n", fname, buffer); } static void md5hash(const char *fname) { int to_child[2]; int to_parent[2]; if (pipe(to_child) != 0 || pipe(to_parent) != 0) err_syserr("failed to create 2 pipes: "); int pid = fork(); if (pid < 0) err_syserr("failed to fork: "); if (pid == 0) be_childish(to_child, to_parent); else be_parental(fname, to_child, to_parent); } int main(int argc, char **argv) { err_setarg0(argv[0]); if (argc <= 1) err_usage("file [...]"); for (int i = 1; i < argc; i++) md5hash(argv[i]); return 0; } ):

pop73

这确认文件已正确复制到子项,输出MD5哈希匹配。

我喜欢涉及子进程和父进程的程序的$ pop73 mm* mm19.c: MD5 1d2207adec878f8f10d12e1ffb8bcc4b mm23.c: MD5 c3948c5a80107fdbfac9ad755e7e6470 mm53.c: MD5 a0a24610400d900eb18408519678481e mm59.c: MD5 1a5b1807c331dd1b5b6ce5f6ffed7c59 $ md5sum mm* 1d2207adec878f8f10d12e1ffb8bcc4b mm19.c c3948c5a80107fdbfac9ad755e7e6470 mm23.c a0a24610400d900eb18408519678481e mm53.c 1a5b1807c331dd1b5b6ce5f6ffed7c59 mm59.c $ be_childish()函数名称。使用离散作业的函数使代码在长期内更易于理解和维护。另请注意,代码关闭文件描述符的程度是多么小心。

经验法则:如果将管道的一端复制到标准输入或标准输出(或标准错误),则应关闭管道的两个端仍在进行中。

be_parental()函数举例说明了这一经验法则。在继续执行命令之前,它会关闭它传递的2个管道的所有4个描述符,因为它已将每个管道中的一个描述符复制到其中一个标准流中。

请注意:如果您不将文件描述符复制到其中一个标准通道,则通常不会立即关闭管道的两个文件描述符。您通常会关闭管道的一端 - 当前流程不会使用的末端。但是另一个是开放的,直到你完成数据处理,无论这意味着什么。 be_childish()函数说明了推论。

答案 1 :(得分:0)

为您的输入提供一些测试用例&amp;输出,你想用echo -n只有n位数或其他什么来实现?我在下面尝试过一些假设。

xyz@xyz-PC:~/s_flow$ cat m5sum.c 
#include<stdio.h>
int main()
{
    int n;
    printf("enter n :\n");
    scanf("%d",&n);
    printf("n = %d \n",n);
    return 0;
}
xyz@xyz-PC:~/s_flow$ echo  12345 | ./m5sum
enter n :
n = 12345

你想要输出如上所述我们如何使用echo?

echo  12345 | ./m5sum 
   |             |        => process1 output will be input for process 2 
process1       process2 

首先你需要一个pipe来写作&amp;阅读,条件是process1不应该在屏幕上显示输出(stdout)所以为此你应该close(1)&amp;这应该是process2的输入,即进程2不应该从用户(stdin)读取,所以做close(0)

这是我的建议

int main()
{
        int p[2];
        pipe(p);
        if(fork()==0)//child
        {
                close(0);//closing std in
                dup(p[0]);//duplicating read end of pipe
                close(p[1]);//closing write end of pipe
                execlp("process1_cmd","cmd_option",NULL);
        }
        else
        {
                close(1);//close stdout
                dup(p[1]);// duplicating write end of pipe
                close(p[0]);//closing read end of pipe  
                execlp("process_2","process_2",NULL);
        }
}

process_1&amp; process_2可以是任何预定义/用户定义的输入命令。我希望它有助于实现你的目标。