猿问

用shell中的管道连接n个命令?

用shell中的管道连接n个命令?

我试图在C中实现一个shell。我可以用一个简单的execvp()来执行简单的命令,但其中一个要求是管理这样的命令:“ls -l | head | tail -4”with a for '循环并且只有一个'pipe()'语句重定向stdin和stdout。几天后,我有点迷失了。

N =简单命令的数量(示例中为3:ls,head,tail)命令=带有命令的结构列表,如下所示:

commands[0].argv[0]: ls
commands[0].argv[1]: -l
commands[1].argv[0]: head
commands[2].argv[0]: tail
commands[2].argv[1]: -4

所以,我做了for循环,并开始重定向stdin和stdout以便用管道连接所有命令,但是...我只是无能为力它为什么不起作用。

for (i=0; i < n; i++){pipe(pipe);if(fork()==0){  // CHILD

    close(pipe[0]);
    close(1);
    dup(pipe[1]);
    close(pipe[1]);

    execvp(commands[i].argv[0], &commands[i].argv[0]);
    perror("ERROR: ");
    exit(-1);}else{      // FATHER

    close(pipe[1]);
    close(0);
    dup(pipe[0]);
    close(pipe[0]);}}

我想要创建的是一系列childed进程:

[ls -l] ---- pipe ----> [head] ---- pipe ----> [tail -4]

所有这些进程都有一个root(运行我的shell的进程)所以,第一个父亲也是shell进程的一个孩子,我已经有点筋疲力尽了,有人可以帮助我吗?

我甚至不确定孩子是否应该是执行命令的孩子。

多谢你们 !!


幕布斯6054654
浏览 511回答 2
2回答

Cats萌萌

这里没有什么复杂的,只要记住最后一个命令应该输出到原始进程'文件描述符1,第一个应该从原始进程文件描述符0读取。你只是按顺序生成进程,沿着输入端传输previois&nbsp;pipe电话。所以,以下是类型:#include&nbsp;<unistd.h>struct&nbsp;command{ &nbsp;&nbsp;const&nbsp;char&nbsp;**argv;};使用简单明确定义的语义创建一个辅助函数:intspawn_proc&nbsp;(int&nbsp;in,&nbsp;int&nbsp;out,&nbsp;struct&nbsp;command&nbsp;*cmd){ &nbsp;&nbsp;pid_t&nbsp;pid; &nbsp;&nbsp;if&nbsp;((pid&nbsp;=&nbsp;fork&nbsp;())&nbsp;==&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(in&nbsp;!=&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dup2&nbsp;(in,&nbsp;0); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close&nbsp;(in); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(out&nbsp;!=&nbsp;1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dup2&nbsp;(out,&nbsp;1); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close&nbsp;(out); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;execvp&nbsp;(cmd->argv&nbsp;[0],&nbsp;(char&nbsp;*&nbsp;const&nbsp;*)cmd->argv); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;return&nbsp;pid;}这是主叉例程:intfork_pipes&nbsp;(int&nbsp;n,&nbsp;struct&nbsp;command&nbsp;*cmd){ &nbsp;&nbsp;int&nbsp;i; &nbsp;&nbsp;pid_t&nbsp;pid; &nbsp;&nbsp;int&nbsp;in,&nbsp;fd&nbsp;[2]; &nbsp;&nbsp;/*&nbsp;The&nbsp;first&nbsp;process&nbsp;should&nbsp;get&nbsp;its&nbsp;input&nbsp;from&nbsp;the&nbsp;original&nbsp;file&nbsp;descriptor&nbsp;0.&nbsp;&nbsp;*/ &nbsp;&nbsp;in&nbsp;=&nbsp;0; &nbsp;&nbsp;/*&nbsp;Note&nbsp;the&nbsp;loop&nbsp;bound,&nbsp;we&nbsp;spawn&nbsp;here&nbsp;all,&nbsp;but&nbsp;the&nbsp;last&nbsp;stage&nbsp;of&nbsp;the&nbsp;pipeline.&nbsp;&nbsp;*/ &nbsp;&nbsp;for&nbsp;(i&nbsp;=&nbsp;0;&nbsp;i&nbsp;<&nbsp;n&nbsp;-&nbsp;1;&nbsp;++i) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pipe&nbsp;(fd); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;f&nbsp;[1]&nbsp;is&nbsp;the&nbsp;write&nbsp;end&nbsp;of&nbsp;the&nbsp;pipe,&nbsp;we&nbsp;carry&nbsp;`in`&nbsp;from&nbsp;the&nbsp;prev&nbsp;iteration.&nbsp;&nbsp;*/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;spawn_proc&nbsp;(in,&nbsp;fd&nbsp;[1],&nbsp;cmd&nbsp;+&nbsp;i); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;No&nbsp;need&nbsp;for&nbsp;the&nbsp;write&nbsp;end&nbsp;of&nbsp;the&nbsp;pipe,&nbsp;the&nbsp;child&nbsp;will&nbsp;write&nbsp;here.&nbsp;&nbsp;*/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close&nbsp;(fd&nbsp;[1]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Keep&nbsp;the&nbsp;read&nbsp;end&nbsp;of&nbsp;the&nbsp;pipe,&nbsp;the&nbsp;next&nbsp;child&nbsp;will&nbsp;read&nbsp;from&nbsp;there.&nbsp;&nbsp;*/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in&nbsp;=&nbsp;fd&nbsp;[0]; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;/*&nbsp;Last&nbsp;stage&nbsp;of&nbsp;the&nbsp;pipeline&nbsp;-&nbsp;set&nbsp;stdin&nbsp;be&nbsp;the&nbsp;read&nbsp;end&nbsp;of&nbsp;the&nbsp;previous&nbsp;pipe &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;and&nbsp;output&nbsp;to&nbsp;the&nbsp;original&nbsp;file&nbsp;descriptor&nbsp;1.&nbsp;*/&nbsp;&nbsp; &nbsp;&nbsp;if&nbsp;(in&nbsp;!=&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;dup2&nbsp;(in,&nbsp;0); &nbsp;&nbsp;/*&nbsp;Execute&nbsp;the&nbsp;last&nbsp;stage&nbsp;with&nbsp;the&nbsp;current&nbsp;process.&nbsp;*/ &nbsp;&nbsp;return&nbsp;execvp&nbsp;(cmd&nbsp;[i].argv&nbsp;[0],&nbsp;(char&nbsp;*&nbsp;const&nbsp;*)cmd&nbsp;[i].argv);}还有一个小测试:intmain&nbsp;(){ &nbsp;&nbsp;const&nbsp;char&nbsp;*ls[]&nbsp;=&nbsp;{&nbsp;"ls",&nbsp;"-l",&nbsp;0&nbsp;}; &nbsp;&nbsp;const&nbsp;char&nbsp;*awk[]&nbsp;=&nbsp;{&nbsp;"awk",&nbsp;"{print&nbsp;$1}",&nbsp;0&nbsp;}; &nbsp;&nbsp;const&nbsp;char&nbsp;*sort[]&nbsp;=&nbsp;{&nbsp;"sort",&nbsp;0&nbsp;}; &nbsp;&nbsp;const&nbsp;char&nbsp;*uniq[]&nbsp;=&nbsp;{&nbsp;"uniq",&nbsp;0&nbsp;}; &nbsp;&nbsp;struct&nbsp;command&nbsp;cmd&nbsp;[]&nbsp;=&nbsp;{&nbsp;{ls},&nbsp;{awk},&nbsp;{sort},&nbsp;{uniq}&nbsp;}; &nbsp;&nbsp;return&nbsp;fork_pipes&nbsp;(4,&nbsp;cmd);}似乎工作。:)

慕码人2483693

首先,你过早地关闭管道。仅关闭当前进程中不需要的结尾,并记住关闭子进程中的stdin / stdout。其次,您需要记住上一个命令中的fd。因此,对于两个进程,这看起来像:int&nbsp;pipe[2];pipe(pipe);if&nbsp;(&nbsp;fork()&nbsp;==&nbsp;0&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Redirect&nbsp;output&nbsp;of&nbsp;process&nbsp;into&nbsp;pipe&nbsp;*/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(stdout); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(pipe[0]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dup2(&nbsp;pipe[1],&nbsp;stdout&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;execvp(commands[0].argv[0],&nbsp;&commands[0].argv[0]);}&nbsp;if&nbsp;(&nbsp;fork()&nbsp;==&nbsp;0&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Redirect&nbsp;input&nbsp;of&nbsp;process&nbsp;out&nbsp;of&nbsp;pipe&nbsp;*/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(stdin); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(pipe[1]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dup2(&nbsp;pipe[0],&nbsp;stdin&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;execvp(commands[1].argv[0],&nbsp;&commands[1].argv[0]);}/*&nbsp;Main&nbsp;process&nbsp;*/close(&nbsp;pipe[0]&nbsp;);close(&nbsp;pipe[1]&nbsp;);waitpid();现在你的工作是为此添加错误处理并为n个进程生成n-1个管道。第一个fork()块中的代码需要为进程1..n-1的相应管道运行,而第二个fork()块中的代码用于进程2..n。
随时随地看视频慕课网APP
我要回答