[转]unix/linux中的dup()系统调用
[转]unix/linux中的dup()系统调用 在linux纷繁复杂的内核代码中,sys_dup()的代码也许称得上是最简单的之一了,但是就是这么一个简单的系统调用,却成就了unix/linux系统最著名的一个特性:输入/输出重定向。
sys_dup()的主要工作就是用来“复制”一个打开的文件号,使两个文件号都指向同一个文件。既然说简单,我们就首先来看一下它的代码(定义在fs/fcntl.c中):
而sys_dup()的主体是dupfd()(定义在同一个文件中):
注:dup和dup2的原型如下:
#include <unistd.h>
int dup(int file_descriptor);
int dup2(int file_descriptor1, int file_descriptor2)
dup返回的文件描述符总是取最小的可用值
dup2返回的文件描述符或者与file_descriptor2相同,或者是第一个大于该参数的可用值。
而这么一个简单的系统调用是如何完成重定向这个艰巨的任务的呢?我们不妨先看个例子。
当我们在shell下输入如下命令:“echo
hello!”,这条命令要求shell进程执行一个可执行文件echo,参数为“hello!”。当shell接收到命令之后,先找到
bin/echo,然后fork()出一个子进程让他执行bin/echo,并将参数传递给它,而这个进程从shell继承了三个标准文件,即标准输入
(stdin),标准输出(stdout)和标准出错信息(stderr),他们三个的文件号分别为0、1、2。而至于echo进程的工作很简单,就是将参数“hello!”写到标准输出文件中去,通常都是我们的显示器上。但是如果我们将命令改成“echo hello! >
foo”,则在执行时输出将会被重定向到磁盘文件foo中(注:重定向于文件描述符有关)。我们假定在此之前该shell进程只有三个标准文件打开,文件号分别为0、1、2,以上命令行将按如下序列执行:
(1) 打开或创建磁盘文件foo,如果foo中原来有内容,则清除原来内容,其文件号为3。
(2) 通过dup()复制文件stdout,即将文件号1出的file结构指针复制到文件号4处,目的是将stdout的file指针暂时保存一下
(3) 关闭stdout,即1号文件,但是由于4号文件对stdout也同时有个引用,所以stdout文件并未真正关闭,只是腾出1号文件号位置。
(4) 通过dup(),复制3号文件(即磁盘文件foo),由于1号文件关闭,其位置空缺,故3号文件被复制到1号,即进程中原来指向stdout的指针指向了foo。
(5)
通过系统调用fork()和exec()创建子进程并执行echo,子进程在执行echo前夕关闭3号和4号文件,只留下0、1、2三个文件,请注意,这
时的1号文件已经不是stdout而是磁盘文件foo了。当echo想向stdout文件写入“hello!”时自然就写入到了foo中。
(6) 回到shell后,关闭指向foo的1号与3号文件文件,再用dup()和close()将2号恢复至stdout,这样shell就恢复了0、1、2三个标准输入/输出文件。
由此可见,当echo程序(或其他)在运行的时候并不知道stdout(对于stdin和stderr同样)指向什么,进程与实际输出文件或设备的结合是在运行时由其父进程“包办”的。这样就简化了子进程的程序设计,因为在设计时只要跟三个逻辑上存在的文件打交道就可以了。可能有人会觉得这很像面向对象中
的多态和重载,没有什么新奇之处,但是如果你活在30甚至40年前,可能你会改变你的看法。
[转]unix/linux中的dup()系统调用的更多相关文章
- linux中的dup()系统调用
参考1:http://www.blogjava.net/lihao336/archive/2011/12/13/366231.html 在linux纷繁复杂的内核代码中,sys_dup()的代码也许称 ...
- 如何设置UNIX/Linux中新创建目录或文件的默认权限
在unix或者linux中,每创建一个文件或者目录时,这个文件或者目录都具有一个默认的权限,比如目录755,文件644,那么这些默认权限是怎么控制的呢? 答案是"umask"权限掩 ...
- unix/linux中图形界面那些事
我们知道unix/linux刚开始的时候是没有图形界面的,随着时代的发展,排版.制图.多媒体应用越来越普遍了,这些需求都需要用到图形界面(Graphical User Interface).为此,MI ...
- Unix/Linux中的grep命令(转)
本文转载自:如何使用Unix/Linux grep命令——磨刀不误砍柴工系列.该博文条理很清晰. grep简介 grep在一个或多个文件中查找与模式字符串(pattern)匹配的行,并将搜索的结果打印 ...
- Unix/Linux中/usr目录的由来
在Linux系统中,有一个很重要的目录——/usr目录.关于这个目录名称的由来,网上主要有下面几种说法: user的缩写 User Shareable Read-only的缩写 Unix/User S ...
- Unix/Linux中shell调用sqlplus的方式
Unix/Linux下,shell脚本调用sqlplus的几种方式介绍: 一.最简单的shell调用sqlplus #!/bin/bash sqlplus -S /nolog > sqlplus ...
- Unix/Linux中的read和write函数
文件描述符 对于内核而言,所有打开的文件都通过文件描述符引用.文件描述符是一个非负整数.当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符.当读或写一个文件时,使用open或creat ...
- Unix/Linux中的fork函数
fork函数介绍 一个现有进程可以调用fork函数创建一个新进程.该函数定义如下: #include <unistd.h> pid_t fork(void); // 返回:若成功则在子进程 ...
- Unix/Linux中Cron的用法
cron是unix或者linux下用来定时任务的命令,大致的用法如下: 1.服务的启动和关闭 /sbin/service crond start //启动服务 /sbin/service cr ...
随机推荐
- 深入理解java集合框架之---------Arraylist集合
ArrayList简介 ArrayLIst是动态数组,用MSDN的说法就是Array的复杂版本,它提供了动态的增加和减少元素,实现了Collection和List接口,可以灵活的设置数组的大小,要注意 ...
- *2_3_5_加入reference model
摘自:http://book.2cto.com/201408/46009.html 在2.1节中讲述验证平台的框图时曾经说过,reference model用于完成和DUT相同的功能. referen ...
- 第十四章、Linux 账号管理与 ACL 权限配置
1. Linux 的账号与群组 1.1 使用者标识符: UID 与 GID 1.2 使用者账号:/etc/passwd 文件结构, /etc/shadow 文件结构 1.3 关于群组: /etc/gr ...
- 帧布局--FrameLayout
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android=" ...
- java并发编程(5)并发程序测试
并发程序测试 一.正确性测试 如:对一个自定义缓存的测试 //自定义的缓存 public class SemaphoreBoundedBuffer <E> { private final ...
- 【angular5项目积累总结】自定义管道 OrderBy
import { Injectable, Pipe } from '@angular/core'; @Pipe({ name: 'orderBy' }) @Injectable() export cl ...
- SQL Serever学习12——数据库的备份和还原
公司的服务器奔溃了,事先没相应的保护措施,使得公司遭到了较大损失,为了以后不再出现类似事件,在系统中引入备份机制,使得数据库被破坏后损失降到最低. 数据的导出和导入 数据转换服务 数据转换服务DTS( ...
- MVC-AOP(面向切面编程)思想-Filter 三种注册方式
在ASP.NET MVC框架中,为我们提供了四种类型的Filter类型包括:IAuthorizationFilter.IActionFilter.IResultFilter.IExceptionFil ...
- 基于Spark GraphX计算二度关系
关系计算问题描述 二度关系是指用户与用户通过关注者为桥梁发现到的关注者之间的关系.目前微博通过二度关系实现了潜在用户的推荐.用户的一度关系包含了关注.好友两种类型,二度关系则得到关注的关注.关注的好友 ...
- vs2015 xamarin 添加智能感知
下载 由于未安装 Xamarin Studio, 不存在android-layout-xml.xsd . schemas.android.com.apk.res.android.xsd 文件. 所以在 ...