题目:设当前目录下有三个二进制格式的可执行程序,文件名分别为cmd1,cmd2和cmd3.
(1).在Bash下的下列命令完成什么功能?
./cmd1 2>&1 | ./cmd2 > r.txt; ./cmd3
(2).编写C语言源程序完成与(1)相同的功能
提示:exec系统调用可用execlp("./cmd1","cmd1",(char *)0);
打开文件用 fd = open("r.txt", O_CREAT | O_TRUNC | O_WRONLY,0666);
dup2系统调用法为dup2(src_fd,dst_fd);
创建管道用pipe(int fds[2]);
等待子进程结束用wait(int staloc);
答:首先说明,0,1,2三个文件说明符分别代表stdin, stdout和stderr。
2>&1的意思是将cmd1的标准输出流和标准错误流合并到标准输出流中;
接下来通过管道将刚才的结果输出到cmd2的输入中;
cmd2>r.txt将cmd2的输出结果重定向到文件r.txt中;
最后是执行cmd3,这与前面的一切都没有关系。(有一点尚存疑问,那就是cmd3是否和cmd1一样,都将stdout和stderr合体了,由于我没有测试错误的用例,因此这里不是标答。)
(2)这题才是重点。首先说明管道和重定向的一些知识。
【 a. 左边的命令应该有标准输出 | 右边的命令应该接受标准输入
左边的命令应该有标准输出 > 右边只能是文件
左边的命令应该需要标准输入 < 右边只能是文件
b. 管道触发两个子进程执行"|"两边的程序;而重定向是在一个进程内执行。】[1]
做这道题之前我接触这方面比较少,下面这段代码参考了不少东西,但是不知来源,没法列举了。这段代码是在一个同学给我的源文件的基础上修改的,因为之前我基本上不会用管道 ( ̄. ̄)
为了能测试,我把虚无缥缈的三个cmd换成了活生生的grep,wc和who ( ̄0  ̄)y
/******************************************************* 使用fork(), exec(), dup2(), pipe() ,open()系统调用 完成与下列shell命令等价的功能。 cmd1:grep -v usr /etc/passwd cmd2:wc -l cmd3:who grep -v usr /etc/passwd 2>&1 | wc -l > r.txt;who ********************************************************/ #include <stdio.h> #include <fcntl.h> #include <unistd.h> int main() { int pfd[2]; /* 建立管道 */ pipe(pfd); if (fork()) /* parent */ { if(!fork()) /* child 2 */ { /* 将标准输出和标准错误重定向到管道写端口pfd[1] */ dup2(pfd[1], 1); dup2(pfd[1], 2); close(pfd[1]); /* 关闭管道读端口pfd[0] */ close(pfd[0]); /* 执行grep */ execlp("/bin/grep", "grep", "-v", "usr","/etc/passwd", NULL); } else { wait(NULL); execlp("/usr/bin/who","who",NULL); /* 这里的who原本是ls,但是ls的结果不能进入stdout,不知为何。 */ } } else /* child 1 */ { /* 打开result.txt文件,若不存在该文件 */ /* 则创建一个新文件并命名为r.txt */ int f = open("r.txt", O_CREAT | O_TRUNC| O_WRONLY, 0666); /* 将标准输入重定向到管道读端口pfd[0] */ dup2(pfd[0], 0); close(pfd[0]); /* 将标准输出重定向到r.txt */ dup2(f, 1); close(f); /* 关闭管道写端口pfd[1] */ close(pfd[1]); /* 执行wc */ execlp("/usr/bin/wc", "wc", "-l", NULL); } }