Linux学习笔记:shell重定向功能中dup/dup2系统调用的作用

        dup和dup2两个系统调用的作用都是拷贝文件描述符。

        在man手册中查询dup和dup2的原型如下:

        #include

        int dup(int oldfd);
        int dup2(int oldfd, int newfd);

        dup用于复制oldfd参数所指的文件描述符,当复制成功时返回最小的尚未被使用的文件描述符。

        dup2区别于dup的地方在于dup2可以指定新文件描述符的数值。若newfd已经被程序使用,系统就会将其关闭以释放该文件描述符,若oldfd与newfd相等,则dup2返回newfd而不关闭它。

        为了更好的理解dup和dup2,先介绍一下文件描述符:

        文件描述符是一个较小的正整数,类似于编号,每个进程在内核的进程控制块(PCB)中都保存着一份文件描述符表,文件描述符就是这个表的索引(每个文件描述符占用表中一个表项),文件描述符表中每个表项都有一个指向已打开文件的指针已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体。当进程用open调用打开一个文件时,内核从可用的文件描述符中选出一个,将其与目标文件相关联。

        所以现在可以这样理解dup和dup2的作用:

        dup从未使用的文件描述符中选出数值最小的一个,将oldfd参数指向的文件描述符中指向文件的指针复制到所选的文件描述符中,即两个新旧文件描述符指向同一个打开的文件(file结构体),两个文件描述符共享文件的偏移量(位置),标志和锁。

        dup2则可以通过参数newfd指定新文件描述符的数值,将oldfd参数指向的文件描述符的文件指针复制到指定文件描述符中(所以当newfd已经指向文件时需要将其先关闭释放),新旧文件描述符指向同一个文件。


        在shell的重定向功能就是通过dup2对标准输入和标准输出的操作来实现的。

        比如如下例程:

        #include
        #include
        #include
        #include
        #include

        int main(int argc,char *argv[])
        {
            int fd;
            fd=open("file.txt",O_WRONLY | O_CREAT,0644);
            dup2(fd,1);
            printf("123456");
           return 0;
        }

        编译运行后,字符串“123456”并没有在终端显示,而是直接保存在了file.txt文件中。原因就是:数值为1的文件描述符本来指向的是标准输出设备文件,但在调用 dup2(fd,1); 之后,数值为1的文件描述符指向的设备文件被关闭,转而指向了fd所指向的文件file.txt,故当进程向标准输出端输出数据时,都相当于对fd所指向的file.txt文件进行操作,所以 printf("123456"); 语句输出的字符串被保存在了file.txt文件中。 shell中的重定向功能就是通过这种方式将命令的输出或者输入定向在某个文件上。

        

         父子进程间的dup/dup2:

         调用fork()产生的子进程和父进程相同的文件描述符对应的文件表项是共享的,即父进程在调用fork()之前的文件描述符所对应的文件表项与子进程相同,共享文件偏移量,所以子进程通过该文件描述符对文件进行读写操作会影响到父进程(父进程同样会影响子进程)。但当父进程调用fork()之后,父子进程各自打开的文件产生的文件描述符不再共享文件表项,两者的文件偏移量不再互相影响(0,1,2属于父进程fork()之前的文件描述符,所以父子进程共享,利用父子进程文件描述符的继承这一点,可以实现父子进程间的通信)。


        小结:dup和dup2是两个非常有用的系统调用,管道 也是利用它们的功能完成的,想要更完整的学习Linux系统,掌握它们的原理与用法是必不可少的步骤。




 


      

 

你可能感兴趣的:(linux,shell)