无名管道(2):shell管道的实现
小技巧:统计一个文件下有多少行代码?
wc -l 文件名
- 就能得到文件的行数
搭配使用
cat pipe.c | wc -l
小技巧:搜索文件里面的内容
grep "#include" 文件名
小技巧:查看命令在什么地方
whereis ls
Shell中的管道通信
管道的作用
- Shell中具有亲缘关系的进程之间传递消息
- 管道的本质是一个字节流
cat pipe.c | wc -l
将标准输出重定向到管道里面
在shell中运行命令
- 基本流程和重定向功能
- 封装成进程:fork/exec系统调用
- 该进程默认打开的stdin、stdout、stderr连接在终端上
- 运行的命令从键盘读取数据并且把输出和错误消息写到屏幕上
- 通过重定向,可以从指定文件读取数据,或将数据输出到指定文件
- 重定向I/O的功能是由shell本事实现的:标准流与文件的连接
- 程序本身并不知道数据最后流向哪里:只是标准流打交道
- 通过命令:cmd>file告诉shell将stdout定位到文件file,于是shell就将文件描述符与指定的文件连接起来,程序的输出到file,而不是默认的屏幕
输入输出重定向
使用ls > log 重定向,是怎么实现重定向的?
就是使用dup函数和dup2函数实现的
重定向一般操作stdin(0)、stdout(1)、stderr(2)这个东西
dup函数和dup2函数
- 将管道和输入输出设备联系起来
- 输入、输出重定向到某个设备、文件
- int dup (int oldfd);
- 打开一个已经存在的文件描述符,返回值为新的文件描述符
- 可以利用这个返回的文件描述符,对这个文件描述符进行文件操作
-
#include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h>int main(void) {int new_fd;new_fd = dup(1);write(1, "hello", strlen("hello"));write(new_fd, "world\n", strlen("world\n"));close(new_fd);return 0; }
int dup2(int oldfd, int newfd);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#define handle_error(s) \{perror(s);exit(-1);}
int main(int argc, char *argv[])
{int fd, new_fd;char *buf = "hello world\n";fd = open("data.log", O_RDWR|O_CREAT, 0664);if (fd == -1)handle_error("open");new_fd = dup2(fd, 1); //把stdout重定向为和fd一模一样的句柄if (new_fd == -1)handle_error("dup2");printf("fd: %d\n new_fd:%d\n", fd, new_fd);write(1, buf, strlen(buf));close(fd);return 0;
}
实验结果:没有输出到屏幕上,重定向到了其他文件,这个用的应该最多
- 实现原理:
- 复制文件描述符:dup2
- 编程练习
- 一个程序的标准输出定向到管道中
- 而另一个程序的标准输入重定向到管道中读取
- 实现步骤
- 定义一个无名管道
- fork,使用两个进程对数据进行收发
- 子进程把标准输出重定向到写管道
- 父进程把标准输入重定向到读管道
- 其实管道的底层实现流程就像下面一样
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>#define handle_error(s) \{perror(s);exit(-1);}int main(int argc, char *argv[])
{int pipe_fd[2];if (pipe(pipe_fd) == -1){perror("pipe");exit(-1);}else{int ret_from_fork = fork();if (ret_from_fork == 0){dup2(pipe_fd[1], 1);execlp("cat", "cat", "dup.c", NULL);}else{dup2(pipe_fd[0], 0);close(pipe_fd[1]);execlp("grep", "grep", "include", NULL);}}return 0;
}
int dup3(int oldfd, int newfd, int flags);