用C实现的一个Bash脚本

题目:设当前目录下有三个二进制格式的可执行程序,文件名分别为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);     } 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wyjjds.html