家具在线设计网站,欧米茄手表价格及图片官方网站,百度极速版免费下载安装,站长统计app文章目录 1. 文件描述符分配规则2. 重定向接口dup2自定义shell重定向(补充) 3. 标准输出和标准错误4. 如何理解一切接文件 本章代码gitee地址#xff1a;文件重定向 1. 文件描述符分配规则
文件描述符的分配规则是从0下标开始#xff0c;寻址最小的没有使用的数组位置#… 文章目录 1. 文件描述符分配规则2. 重定向接口dup2自定义shell重定向(补充) 3. 标准输出和标准错误4. 如何理解一切接文件 本章代码gitee地址文件重定向 1. 文件描述符分配规则
文件描述符的分配规则是从0下标开始寻址最小的没有使用的数组位置它的下标就是新文件的文件描述符。
我们来看一个现象
#includestdio.h
#includeunistd.h
#includesys/types.h
#includesys/stat.h
#includefcntl.h
#includestring.h#define filename log.txt
int main()
{close(1);int fd open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666);if(fd 0){perror(open);return 1;}const char *str hello linux\n;int cnt 5;while(cnt--){write(1,str,strlen(str));}close(fd);return 0;
}这段代码本应该是想1号文件描述符写入也就是向显示屏输出信息。我们将这个1号文件描述符指向的显示器文件关闭了运行结果没有显示出来这个符合预期。可是我们发现原本应该向显示器文件写入的内容却写进了log.txt这个文件。 这个过程就叫做——输出重定向。 我们将1号文件描述符关闭将进程与显示器对应的关联关系去掉。这个1号位置就空出来了然后我们重新打开一个文件那么正好1号文件描述符指向的内容是空的然后就与该文件建立关联关系所以内容写入这个文件 2. 重定向接口
如果我们想将某个内容重定向其实不需要我们自己每次都手动关闭某个文件描述符再去覆盖系统为我们还提供了一些接口。
dup2
man 2 dup2这里的并不是拷贝文件描述符因为文件描述符只是一个数组的下标本质上拷贝的是文件描述符指向的内容
#includestdio.h
#includeunistd.h
#includesys/types.h
#includesys/stat.h
#includefcntl.h
#includestring.h#define filename log.txt
int main()
{//close(1);int fd open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666);if(fd 0){perror(open);return 1;}dup2(fd,1);close(fd);const char *str hello linux\n;int cnt 5;while(cnt--){write(1,str,strlen(str));}//close(fd);return 0;
}我们这里就能看到原本应该向显示器文件输出的内容重定向到了log.txt文件当中。
重定向的本质就是将文件描述表当中的文件地址做拷贝。
自定义shell重定向(补充)
有了这些知识原理就能写出自己的重定向代码 不了解的可以查看这篇文章——Linux实现简易shell #define NONE -1
#define IN_RDIR 0
#define OUT_RDIR 1
#define APPEND_RDIR 2
char *rdirfilename NULL;
int redir NONE;void check_redir(char *cmd)
{char *pos cmd;while(*pos){if(*pos ){if(*(pos1) ){*pos \0;*pos \0;while(isspace(*pos)) pos;rdirfilename pos;redir APPEND_RDIR;break;}else{*pos \0;while(isspace(*pos)) pos;rdirfilename pos;redir OUT_RDIR;break;}}else if(*pos ){*pos \0;while(isspace(*pos)) pos;rdirfilename pos;redir IN_RDIR;break;}else{//不改变}pos;}
}void normalExcute(char *_argv[])
{pid_t id fork();if(id 0){perror(fork fail);return; }else if(id 0){//判断是否重定向int fd 0;if(redir IN_RDIR) //输入重定向{fd open(rdirfilename,O_RDONLY);dup2(fd,0);}else if(redir OUT_RDIR) //输出重定向{fd open(rdirfilename,O_CREAT|O_WRONLY|O_TRUNC,0666);dup2(fd,1);}else if(redir 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);}}
}这里的重定向并不会影响到之后的程序替换 因为这里的进程结构体或者是文件结构体都是属于内核的数据结构而我们的程序替换是由程序地址空间通过页表来进行一个替换这也将程序替换和重定向工作进行了解耦 3. 标准输出和标准错误
标准输出stdou和标准错误stderr都是显示器文件输出内容那他们这两个有什么区别呢
#includestdio.h
#includeunistd.h
#includesys/types.h
#includesys/stat.h
#includefcntl.h
#includestring.h#define filename log.txt
int main()
{fprintf(stdout,hello stdout\n);fprintf(stdout,hello stdout\n);fprintf(stdout,hello stdout\n);fprintf(stderr,hello stderr\n);fprintf(stderr,hello stderr\n);fprintf(stderr,hello stderr\n);return 0;
}这里我们运行确实是发现都是往显示器文件上输出内容 但是如果我们重定向这里发现往标准错误输入的内容并没有重定向到我们的目标文件当中而标准输出的内容被重定向到了目标文件 通过这里我们可以验证这个输出重定向的符合默认就是将一个号文件描述符的内容重定向到目标 但是我们也可以指定将几号文件描述符指向的内容重定向到目标文件当中 这里有个21意思就是将一号文件描述符的内容拷贝到二号文件描述符当中让其和1指向同一个文件 4. 如何理解一切接文件
所以操作计算机的动作都是以进程的形式进行操作的所以访问文件的操作也都是以进程的形式访问的。
在计算机里面存在着各种设备例如键盘、显示器、磁盘、网卡…这些都被称之为外设。
操作系统和这些外设打交道的时候都需要它们所对应的方法例如显示要有读的方法、键盘要有读写方法…每个外设都要有其对应读写方法这个简称为IO。
因为在linux下一切皆文件所以在操作系统看来这些外设都是文件而访问文件的操作都是以进程的形式访问。linux内核里面又提供了一个方法表的结构struct operation_func这里面包含了一些函数指针函数指针可以调用这些外设的读写方法。
每打开一个文件就会为其创建一个方法集对象而在struct file中又包含了一些指针其中就有一个可以指向这个方法集。
那么在进程创建的时候进程有对应的文件描述符表这个表就能指向这些文件我们用户就提供系统调用来访问这些文件。
所以从这个struct file往上我们并不用关心底层访问的是什么东西我们看到就是一切皆文件 这里指针指向哪一个对象就访问哪一个对象这个不就是多态的逻辑吗