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) 也是大同小异。


  • 相关阅读:
    安卓手机数据库和自动寻路插件
    快速找图找字插件
    大龙快速找图,找字插件
    C星【多线程】寻路插件最新更新2019-8-17
    大龙数据库插件,通用所有数据库,支持任何语言调用
    开源一个自己造的轮子:基于图的任务流引擎GraphScheduleEngine
    Java中使用CountDownLatch进行多线程同步
    TensorFlow实验环境搭建
    Java中Semaphore(信号量)的使用
    CNN在中文文本分类的应用
  • 原文地址:https://www.cnblogs.com/firstrate/p/3286357.html
Copyright © 2011-2022 走看看