管道和重定向
输入输出不仅可以重定向到文件,也可以通过管道传递到其他进程中。
基本思路:
linux:
1. 创建管道对
pipe(int pipefd[2])
2. 创建进程
首先fork,然后子进程用dup2把pipefd[0]复制到STDIN_FILENO(就是0),然后关闭pipefd[1],或者把pipefd[1]复制到STDOUT_FILENO(就是1),然后关闭pipefd[0]。
之后调用exec去载入要创建的进程。
3. 读或写
用read或者write。注意读写之前要把子进程使用的那一个用close函数关闭掉。
区别在*nix创建进程分两步,fork然后exec。windows只一步。
区别2,*nix要手工dup来复制文件描述符,windows在创建进程的API内部做好了这件事。
linux步骤多一些,但是灵活,可以变化出多种模式来,例如fork之后,不仅仅子进程可以exec,父进程也可以exec,完完全全实现像“ls|wc -l”这样的功能。也就是子进程用wc去替代,父进程用ls去替代。
windows步骤少,模式固定,它要实现上述功能,反而更加繁琐,需要创建两个进程,并把它们对接,然后等待两个进程结束
实例:
题目:通过管道模拟shell命令:catfile | sort
涉及主要知识点:未命名管道、重定向
题目描述:具体模拟一个shell命令:cat file | sort。具体的一些提示在后面。
提示:首先在当前目录下创建一个名为”file”的文件,里面的内容输入如下:
99
123
892
12
1342
89
32
76
通过执行”cat file | sort”后的结果如下:
12
123
1342
32
76
89
892
99
现在我们需要通过一个管道,将”cat file”的结果通过管道送给命令”sort”。其中,将”cat file”命令的输出结果重定向到”sort”命令的输入是由包含在命令中的管道标志”|”来完成的。为了在程序当中实现类似的功能,需要用dup()或者dup2()系统调用将标准输入和标准输出联系起来,具体的系统调用使用可以通过man手册来查,或者查阅群共享里面的函数手册。另外,这里的”cat file”和”sort”命令不是自己来完成,而是通过调用exec函数族来实现的。
******************************************************************************************************************************************
******************************************************************************************************************************************
我的源代码如下:
1 #include <stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<unistd.h> 5 #include<sys/types.h> 6 #include<sys/stat.h> 7 8 int main(intarg,char *argv[],char **environ) 9 { 10 int fd[2]; 11 pid_t pid; 12 int stat_val; 13 14 if(arg < 2) 15 { 16 printf("wrong parameters\n"); 17 exit(0); 18 } 19 if(pipe(fd)) 20 { 21 printf("Create pipefailed!\n"); 22 exit(1); 23 } 24 25 pid=fork(); 26 switch(pid) 27 { 28 case -1: 29 perror("forkfailed!\n"); 30 exit(1); 31 case 0: 32 //close(0); 33 //dup(fd[0]); 34 dup2(fd[1],1); 35 close(fd[0]); 36 execlp("cat","cat","file",NULL); 37 exit(0); 38 default: 39 dup2(fd[0],0); 40 close(fd[1]); 41 execlp("sort","sort",NULL); 42 exit(0); 43 } 44 wait(&stat_val); 45 exit(0); 46 return 0; 47 } ****************************************************************************************************************************************** ****************************************************************************************************************************************** 编译sort.c: jingjing@jingjing-laptop:~/公共的$ gccsort.c -o sort 运行程序: jingjing@jingjing-laptop:~/公共的$ ./sortcat file|sort 12 123 1342 32 76 89 892 99 *****
流程图:
1』pipe()创建管道、fork()创建子进程
注意: 关于这里 在父、子进程中都需要 close() 两次 有待验证!
心得:
1
子进程的功能是读出信息,而父进程的功能是写入信息;因此在子进程那里,要把管道的输入端复制到标准输出中,即dup2(fd[1],1)而父进程则要把管道写端复制到标准输入,即dup2(fd[0],0)。
2
dup()与dup2()的最大区别:
举例说明:
close(1); //关闭标准输出
dup(fd[1]); //把管道的输入端复制到标准输出
这两个语句等价于: dup2(fd[1],1);
所以dup2()是把close()和dup()这两个函数集成在了同一个函数里。这里特别要注意的是:dup2()的两个参数,是把前一个复制到后一个里面,所以书上的例子中写的是错误的。
3、还有就是exec()函数的用法,我一开始不知道“cat file“命令如何作为函数的参数,现在谈谈我的理解吧:
我的程序中execlp("cat","cat","file",NULL);第一个参数是为了指明该命令的路径,第二个和第三个参数是该命令
所包含的所有参数,即把他们一一罗列出来。