Chinaunix首页 | 论坛 | 博客
  • 博客访问: 339091
  • 博文数量: 46
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 562
  • 用 户 组: 普通用户
  • 注册时间: 2013-05-14 13:32
个人简介

先知者为师

文章分类

全部博文(46)

文章存档

2016年(1)

2015年(6)

2014年(20)

2013年(19)

我的朋友

分类: LINUX

2014-02-22 12:27:38

Bourne Shell 的I/O重定向的语法是2>&1.意在通知shell把标准错误重定向到标准输出。
如:
        $ ./myscript >results.log 2>&1
1.    shell 通过赋值文件描述符2实现了标准错误的重定向操作,因此文件描述符2和描述符1向同一个文件句柄
文件句柄参考文献[TLPL.Michael Kerrisk 2014]中文版。
2.请注意要满足shell这一要求,仅仅简单的打开(open)results.log 文件两次是远远不够的
    首先两个文件描述符不能共享文件偏移量指针,因此有可能导致相互覆盖的输出,
    其次打开的文件不一定就是磁盘文件,如下命令,标准输出和标准错误将一起送达同一个管道:
        $ ./myscript 2>$1 | less

那么我们的主角出场了 dup(),和dup2(),dup3().
因为的系统调用,故其头文件在中被声明。


dup和dup2也是两个非常有用的调用,它们的作用都是用来复制一个文件的描述符。它们经常用来重定向进程的stdin、stdout和stderr。这两个函数的 原形如下:
    #include
    int dup( int oldfd );
    int dup2( int oldfd, int targetf

利用函数dup,我们可以复制一个描述符。传给该函数一个既有的描述符,它就会返回一个新的描述符,这个新的描述符是传给它的描述符的拷贝。这意味着,这两个描述符共享同一个。例如,如果我们对一个文件描述符执行lseek操作,得到的第一个文件的位置和第二个是一样的。下面是用来说明dup函数使用方法的代码片段:
    int fd1, fd2;
    ...
    fd2 = dup( fd1 );
    需要注意的是,我们可以在调用fork之前建立一个描述符,这与调用dup建立描述符的效果是一样的,子进程也同样会收到一个复制出来的描述符。 
dup2函数跟dup函数相似,但dup2函数允许调用者规定一个有效描述符和目标描述符的id。dup2函数成功返回时,目标描述符(dup2函数的第二个参数)将变成源描述符(dup2函数的第一个参数)的复制品,换句话说,两个文件描述符现在都指向同一个文件,并且是函数第一个参数指向的文件。下面我们用一段代码加以说明:
    int oldfd;
    oldfd = open("app_log", (O_RDWR | O_CREATE), 0644 );
    dup2( oldfd, 1 );
    close( oldfd );
    本例中,我们打开了一个新文件,称为“app_log”,并收到一个文件描述符,该描述符叫做fd1。我们调用dup2函数,参数为oldfd和1,这会导致用我们新打开的文件描述符替换掉由1代表的文件描述符(即stdout,因为标准输出文件的id为1)。任何写到stdout的东西,现在都将改为写入名为“app_log”的文件中。需要注意的是,dup2函数在复制了oldfd之后,会立即将其关闭,但不会关掉新近打开的文件描述符,因为文件描述符1现在也指向它。 

铺垫已经做完 那么我们来看看具体的实现:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>

  4. int main(int argc, const char *argv[])
  5. {

  6.     int fd;
  7.     fd = dup2(STDOUT_FILENO,STDERR_FILENO);
  8.     if (fd == -1)
  9.     {
  10.         perror("dup2");
  11.         _exit(EXIT_FAILURE);
  12.     }
  13.     
  14.     fprintf(stdout,"hello world!\n");
  15.     fprintf(stderr,"hello error!\n");
  16.     return 0;
  17. }
显示结果:

瞧瞧,没有覆盖,在后边写入的,为什么stdout在前面反而写输出到后边呢? 
这里有个解释:
流缓冲的属性:
缓冲区类型有:全缓冲(大部分缓冲都是这类型)、行缓冲(例如stdio,stdout)、无缓冲(例如stderr )。
关于全缓冲,例如普通的文件操作,进行fputs、fprintf操作后,数据并没有立即写入磁盘文件中,当fflush或fclose文件时,数据才真正写入。
因为我们重定向到文件 test.txt了 也就是对普通文件的操作,所以变成全缓冲了。
阅读(1674) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~