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

基本上我想在C中实现这样的东西:

output=$(echo -n 1234 | md5sum)

1234是输入,md5sum是我想要运行的程序。

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

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

一些帖子似乎暗示pipe与dup2或其他一些功能,但他们没有解释如何使它们工作。

答案

popen() could be used

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

output=$(echo -n 1234 | md5sum)

这可以用C语言写成popen():

#include

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并不是完全可移植的。有空间认为你期待第二个命令的输出。)

If you want two-way communication

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

#include

#include

#include

#include

#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):

$ 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

$

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

我喜欢涉及子进程和父进程的程序的be_childish()和be_parental()函数名称。使用离散作业的函数使代码在长期内更易于理解和维护。另请注意,代码关闭文件描述符的注意事项。

经验法则:如果将管道的一端复制到标准输入或标准输出(或标准错误),则应在继续之前关闭管道的两端。

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

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

另一答案

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

xyz@xyz-PC:~/s_flow$ cat m5sum.c

#include

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进行写作和阅读,条件是process1不应该在屏幕上显示输出(stdout)所以为此你应该close(1)&这应该输入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和process_2可以是任何预定义/用户定义的输入命令。我希望它有助于实现你的目标。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值