Linux系统编程:dup2()重定向

系统 1518 0

对于 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\n");

close(p[READ]);

dup2(p[WRITE], 1);

close(p[WRITE]);

printf("4556\n");

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

}


加入了 2 printf , 但是只有 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] 中。刚开始有个迷惑,就是既然已经 close 1 )了,为什么还能输入到 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!\n
      
      
        "
      
      
        );

      
      
        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\n
      
      
        "
      
      
        , 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!\n
      
      
        "
      
      
        );

      
      
        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\n", 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...\n
      
      
        "
      
      
        );

      
      
        25
      
      
        if
      
      (write(STDOUT_FILENO, buf, n) !=
      
         n)

      
      
        26
      
      
                {

      
      
        27
      
                   perror(
      
        "
      
      
        write error!
      
      
        "
      
      
        );

      
      
        28
      
      
        return
      
      (
      
        1
      
      
        );

      
      
        29
      
      
                }

      
      
        30
      
               printf(
      
        "
      
      
        end to write...\n
      
      
        "
      
      
        );   

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


Linux系统编程:dup2()重定向


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论