文章目录
目录
文章目录
前言
一、函数的认识
1、认识close函数和dup2函数
1、close函数:
编辑
2、write、read函数
1、write函数
2、read函数
二、重定向
1.引入函数dup2
编辑
2、输出重定向
3.输出重定向
三、myshell重定向
总结
前言
接上一篇,我们回顾了c语言所学的基本函数还有open函数,fopen的c接口封装。
linux——基础io
int main()
{close(1); int n = printf("stdin->fd: %d\n", stdin->_fileno);printf("stdout->fd: %d\n", stdout->_fileno);printf("stderr->fd: %d\n", stderr->_fileno);fprintf(stderr, "printf ret: %d\n", n);
}
思考:为什么加了close(1)没有打印标准io流的下标?
一、函数的认识
1、认识close函数和dup2函数
1、close函数:
通过man 3 close查看文档
通过文档我们知道了close是关闭一个打开通道,而参数就是下图中的files_struct这个结构体中fd这个数组的下标。
答思考题:因为我们close(1),所以1号通道被关闭,1号通道就是标准输出,所以就无法向显示器上打印。
2、write、read函数
1、write函数
在2号手册:
2、read函数
2号手册
二、重定向
1、close后的底层
我们知道close以后,指定的通道会被关闭,而新建一个文档,文档会往下标小的,并且那个位置没有存放任何流的位置存放。如果我们将stderr(fd=2)流关闭,然后再新建一个文档会怎么样呢?
int main()
{close(2); int fd=open("mytest.txt",O_CREAT|O_WRONLY|O_APPEND,0666);if(fd<0){perror("open");return -1;}printf("fd->%d\n",fd);close(fd);
}
此时,我们发现,本来应该输出到显示器上的内容,输出到了文件 myfile 当中,其中,fd=1。这种现象叫做输出 重定向。常见的重定向有:>, >>, < 那重定向的本质是什么呢?
1.引入函数dup2
- dup:返回的新文件描述符是最小的尚未被使用过的文件描述符。如果原始文件描述符为3,那么使用dup函数复制后得到的新文件描述符可能是4、5等。
- dup2:允许用户通过第二个参数指定新文件描述符。如果原始文件描述符为3,可以通过dup2(3, 4)指定新文件描述符为4。
dup2将newfd拷贝给oldfd这个地址上内容,然后dup2会自动close(newfd);
最后保留下来的是oldfd;
2、输出重定向
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {int fd = open("mytest1.txt", O_CREAT | O_RDWR);if (fd < 0) {perror("open");return 1;}dup2(fd, 1);//将fd的file*拷贝到1的位置,然后1这个位置原有的stdout就不存在了。clonse(fd)write(1,"12345\n",5);//写当了下边为1的位置close(fd);return 0;
}
我们以读写的方式打开文件,然后将fd拷贝到stdout的位置,然后将fd colse掉然后向1中写入数据,现象为还是向文件中写入
3.输出重定向
代码如下(示例):
int fd = open(filename, O_RDONLY);if(fd < 0){perror("open");return 1;}//dup2(fd, 0);close(fd);
char inbuffer[1024];ssize_t s = read(0, inbuffer, sizeof(inbuffer)-1);if(s>0){inbuffer[s] = '\0';printf("echo# %s\n", inbuffer);}
int fd = open(filename, O_RDONLY);if(fd < 0){perror("open");return 1;}dup2(fd, 0);close(fd);
char inbuffer[1024];ssize_t s = read(0, inbuffer, sizeof(inbuffer)-1);if(s>0){inbuffer[s] = '\0';printf("echo# %s\n", inbuffer);}
三、myshell重定向
宏和全局变量
#define NONE -1
#define IN_RDIR 0
#define OUT_RDIR 1
#define APPEND_RDIR 2char *rdirfilename = NULL;
int rdir = NONE;
void check_redir(char *cmd)
{// ls -al -n// ls -al -n >/</>> filename.txtchar *pos = cmd;while(*pos){if(*pos == '>'){if(*(pos+1) == '>'){*pos++ = '\0';*pos++ = '\0';while(isspace(*pos)) pos++;rdirfilename = pos;rdir=APPEND_RDIR;break;}else{*pos = '\0';pos++;while(isspace(*pos)) pos++;rdirfilename = pos;rdir=OUT_RDIR;break;}}else if(*pos == '<'){*pos = '\0'; // ls -a -l -n < filename.txtpos++;while(isspace(*pos)) pos++;rdirfilename = pos;rdir=IN_RDIR;break;}else{//do nothing}pos++;}
}
子进程进行修改
void NormalExcute(char *_argv[])
{pid_t id = fork();if(id < 0){perror("fork");return;}else if(id == 0){int fd = 0;// 后面我们做了重定向的工作,后面我们在进行程序替换的时候,难道不影响吗???if(rdir == IN_RDIR){fd = open(rdirfilename, O_RDONLY);dup2(fd, 0);}else if(rdir == OUT_RDIR){fd = open(rdirfilename, O_CREAT|O_WRONLY|O_TRUNC, 0666);dup2(fd, 1);}else if(rdir == APPEND_RDIR){fd = open(rdirfilename, O_CREAT|O_WRONLY|O_APPEND, 0666);dup2(fd, 1);}//让子进程执行命令//execvpe(_argv[0], _argv, environ);execvp(_argv[0], _argv);exit(EXIT_CODE);}else{int status = 0;pid_t rid = waitpid(id, &status, 0);if(rid == id) {lastcode = WEXITSTATUS(status);}}
}
总结
- 重定向标准输入/输出:这是最常见的用法,特别是在子进程中,将标准输入、输出或错误输出重定向到其他文件描述符,这样标准输出就可以写在其他文件描述符对应文件了。
- 文件描述符的复制:在不同函数或线程中共享同一个文件描述符,以便不同的代码部分可以对同一个文件进行操作。