zoukankan      html  css  js  c++  java
  • Linux系统编程:dup2()重定向

    对于Dup2 的理解:

    源代码:

     

     1 #include <unistd.h>
     2 #include <stdio.h>
     3 #include <stdlib.h>
     4 #include <string.h>
     5 #include <time.h>
     6 
     7 #define MSGSIZE 20
     8 #define READ 0 
     9 #define WRITE 1
    10 
    11 int main(int argc, char const *argv[])
    12 {
    13     int p[2], bytes, res, c;
    14     char inbuf[10240];
    15     int pid;
    16     printf("%c", 11);
    17     if(pipe(p) == -1){// creat the pipe , if pipe is built failed , exit .
    18         perror("pip call");
    19         exit(1);
    20     }
    21     pid = fork();
    22     if(pid != 0){// creat parent pid and child pid.
    23         close(p[READ]);//close parent pipe read 
    24         dup2(p[WRITE], 1);
    25         close(p[WRITE]);//close parent pipe write
    26         execlp(argv[1], argv[1], NULL);
    27     }
    28     else{
    29 
    30         close(p[WRITE]);//close child pipe write
    31         
    32         dup2(p[READ],0);
    33 
    34         close(p[READ]);//close child pipe read
    35 
    36         execlp(argv[2], argv[2], NULL);
    37     }
    38     return 0;
    39 }

    通过命令行输出:

    ./a.out “ls” “ps”

    仅仅在终端执行了ps的命令, 而没有看到ls 命令的结果。

    因此,开始走入了第一个误区:父进程没有执行

    通过调试 在父进程执行if条件中加入以下代码:

    if(pid != 0){

    printf("4556 ");

    close(p[READ]);

    dup2(p[WRITE], 1);

    close(p[WRITE]);

    printf("4556 ");

    execlp(argv[1], argv[1], NULL);

    }


    加入了2printf , 但是只有dup2 上面的printf 结果输出到屏幕上,因此我注释了 dup2(p[WRITE], 1); 结果在父进程if语句中的dup2 后面的命令都执行并且输出到屏幕上了。通过查找dup2 命令发现了重定向的强大之处。


    先解释下 dup2 命令,

    int dup2(int filedes, int filedes2);

    说明:

    dup2 则可以用filedes2 参数指定新描述符的数值。如果filedes2 已经打开,则先将其关闭。如若filedes 等于filedes2,则返回filedes2,而不关闭它。

    dup2(p[WRITE], 1); 这句话可以理解为将标准输出重定向到 p[WRITE], 因此在这句话后面的所有printf 语句打印或者exec 执行的内容都输入到了p[WRITE]中。刚开始有个迷惑,就是既然已经close1)了,为什么还能输入到p[WRITE]中,通过自己的直觉判断,应当是close(1)关闭了屏幕的输出,但是它有缓冲区保存printf打印出的内容,并且由于重定向的关系,输进了p[WRITE]中。

     

    代码:

     

     1 #include <unistd.h>
     2 #include <stdio.h>
     3 #include <stdlib.h>
     4 #include <string.h>
     5 #include <time.h>
     6 
     7 #define MSGSIZE 20
     8 #define READ 0 
     9 #define WRITE 1
    10 
    11 int main(int argc, char const *argv[])
    12 {
    13     int p[2], bytes, res, c;
    14     char inbuf[10240];
    15     int pid;
    16     printf("%c", 11);
    17     if(pipe(p) == -1){// creat the pipe , if pipe is built failed , exit .
    18         perror("pip call");
    19         exit(1);
    20     }
    21     pid = fork();
    22     if(pid != 0){// creat parent pid and child pid.
    23         close(p[READ]);//close parent pipe read 
    24         dup2(p[WRITE], 1);
    25         close(p[WRITE]);//close parent pipe write
    26         printf("123!
    ");
    27         execlp(argv[1], argv[1], NULL);
    28         perror("execlp");//error output
    29     }
    30     else{
    31         while(1){
    32             res = read(p[READ], inbuf, 10240);
    33                 if(res>0)
    34                     printf("%s
    ", inbuf);
    35             break;
    36         }
    37 
    38         close(p[WRITE]);//close child pipe write
    39         
    40         dup2(p[READ],0);
    41 
    42         close(p[READ]);//close child pipe read
    43 
    44         execlp(argv[2], argv[2], NULL);
    45     }
    46     return 0;
    47 }

     

     

    通过在子进程中用while(1)循环读取p[READ]内容,发现读出了父进程本应在屏幕上打印的内容,因此父进程是执行了所有命令行,只是通过重定向命令存到了p[WRITE]管道中。

    由于有dup2(p[READ], 0) 命令,因此猜测标准输入的文件描述符定向到了p[READ] , 因此如果猜测没错,通过getchar()读取文件标准输入并把P[READ]的内容输出到屏幕上则证明我猜想没错。

    代码:

     

     1 #include <unistd.h>
     2 #include <stdio.h>
     3 #include <stdlib.h>
     4 #include <string.h>
     5 #include <time.h>
     6 
     7 #define MSGSIZE 20
     8 #define READ 0 
     9 #define WRITE 1
    10 
    11 int main(int argc, char const *argv[])
    12 {
    13     int p[2], bytes, res, c;
    14     char inbuf[10240];
    15     int pid;
    16     printf("%c", 11);
    17     if(pipe(p) == -1){// creat the pipe , if pipe is built failed , exit .
    18         perror("pip call");
    19         exit(1);
    20     }
    21     pid = fork();
    22     if(pid != 0){// creat parent pid and child pid.
    23         close(p[READ]);//close parent pipe read 
    24         dup2(p[WRITE], 1);
    25         close(p[WRITE]);//close parent pipe write
    26         printf("123!
    ");
    27         execlp(argv[1], argv[1], NULL);
    28         perror("execlp");//error output
    29     }
    30     else{
    31         // while(1){
    32         //     res = read(p[READ], inbuf, 10240);
    33         //         if(res>0)
    34         //             printf("%s
    ", inbuf);
    35         //     break;
    36         // }
    37 
    38         close(p[WRITE]);//close child pipe write
    39         
    40         dup2(p[READ],0);
    41         while((c=getchar()) != -1){
    42             printf("%c", c);
    43         }
    44         close(p[READ]);//close child pipe read
    45 
    46         execlp(argv[2], argv[2], NULL);
    47     }
    48     return 0;
    49 }


    通过在dup2(p[READ], 0) 后面while循环读入输入流输入的字符并且打印出来, 发现结果果然是p[READ]的内容,猜疑没错。


    为了更清楚的理解dup2的重定向含义,想理解dup2(fd,0)dup2(0,fd)功能相同吗?

    为了得到答案,找些资料发现,答案是不同。

     

    测试代码:

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <fcntl.h>
     4 
     5 #define BUFMAXSIZE 4096
     6 
     7 int main(int argc, char *argv[])
     8 {
     9     int fd;
    10     int n;
    11     char buf[BUFMAXSIZE];
    12     int fs;
    13     fs = open("test", O_RDWR);   
    14     if((fd = open("duan", O_RDWR )) == -1)
    15     {
    16         perror("open error!");
    17         return(1);
    18     }
    19    
    20     dup2(fd, 1);       // dup2(0,fd);
    21    
    22     while((n = read(fs, buf, BUFMAXSIZE)) > 0)
    23     {
    24         printf("begin to read...
    ");
    25         if(write(STDOUT_FILENO, buf, n) != n)
    26         {
    27             perror("write error!");
    28             return(1);
    29         }
    30         printf("end to write...
    ");   
    31     }
    32     if(n < 0)
    33     {
    34         perror("read error");
    35         return(1);
    36     }
    37 
    38     return 0;
    39 } 

     

    dup(fd, 0) 这段代码测试, 打印出了 duan 文件里面的内容。

    之后创建个文件 Levi 里面写和duan 文件不同的内容。

    通过./a. out < Levi输出:

    第一个输出是 dup(fd, 0) 输出了Duan 文件的内容。即是fd的内容

    第二个输出是 dup(0, fd) 输出了 Levi 文件的内容。即是 通过文件重定向到标准输入的内容。

    从图中的输出结果已经可以看到两者的区别了。

    第一种dup2(fd,0)之前已经将 fd 初始化指向到文本 Duan了,

    并且不会被后面的代码所修改。

    第二种dup2(0,fd)则将 fd 重新指向到文件描述符0所代表的文件(即终端标准输入)了。

    那么可以看到,程序的执行中不会再读取 Duan 文件了。

    而是进入了一种交互模式。

    另外,这时“输入重定向”也可以生效了。

    文件描述符0被 “<” 重定向到 Duan

    所以,这里直接输出了该文本的内容。

    dup2(fd,0) 相当于“输入重定向”的功能,

    dup2(0,fd) 不是表示 fd 所指的文件接收来自终端的输入,因为,fd 已经不再指向原来的那个文件了。

    它和文件描述符0 已经在共享同一个文件表项(即指向终端标准输入的那个表项)了。

    输出重定向”的功能可以用 dup2(fd ,1) 替代。

    dup2(fd,1) dup2(1,fd) 也是大同小异。


  • 相关阅读:
    现代软件工程 第一章 概论 第3题——韩婧
    现代软件工程 第一章 概论 第2题——韩婧
    小组成员邓琨、白文俊、张星星、韩婧
    UVa 10892 LCM的个数 (GCD和LCM 质因数分解)
    UVa 10780 幂和阶乘 求n!中某个因子的个数
    UVa 11859 除法游戏(Nim游戏,质因子)
    Codeforces 703C Chris and Road 二分、思考
    Codeforces 703D Mishka and Interesting sum 树状数组
    hdu 5795 A Simple Nim SG函数(多校)
    hdu 5793 A Boring Question 推公式(多校)
  • 原文地址:https://www.cnblogs.com/firstrate/p/3286357.html
Copyright © 2011-2022 走看看