Linux 输出重定向 “>”“>>”“freopen”

Posted cpp_learners

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux 输出重定向 “>”“>>”“freopen”相关的知识,希望对你有一定的参考价值。

有时候,我们编码时会使用printf或fprintf去打印输出调试信息或者报错信息,但正常这样去打印,只会显示在终端,如果终端关闭了,或者系统宕机了等,这些输出信息就没有了,为了将这些重要的信息保存下来,可以输出重定向到文件,将这些信息直接输出到文件中保存着。


Linux的本质就是一切皆文件,输入输出设备也是以文件形式存在和管理的。

任何一个程序在Linux中运行,Linux系统都会为其创建3个已经打开的stream,分别用来输入(0:stdin),输出(1:stdout),打印诊断和错误信息(2:stderr)。通常他们会被连接到用户终端。这3个句柄的类型为指向FILE的指针。可以被fprintf、fread等函数使用,他们在程序开始启动后,stdin, stdout, and stderr 的文件描述符是 0, 1和2,其它的文件描述符则排在其后。

注意:stderr是不缓存的,stdout则是有缓存。

意思是:有缓存功能的,直到遇到回车'\\n'才会进行打印输出,否则一直留在缓冲区里;而没有缓存功能的没有任何限制,直接打印输出。例:

#include <unistd.h>
#include <stdio.h>


int main(int argc, char **argv) 
    
    for (int i = 0; i < 5; i++) 
        //fprintf(stdout, "This is stdout[%d]\\n", i);
		fprintf(stdout, "This is stdout[%d]", i);
        sleep(1);
    

    fprintf(stdout, "\\n");

    for (int i = 0; i < 5; i++) 
        fprintf(stderr, "This is stderr[%d]", i);
        sleep(1);
    

    fprintf(stderr, "\\n");
    sleep(5);

    return 0;

 可以看出,第一个for循环中输出的语句是一起输出的,它是遇到fprintf(stdout, "\\n");这行代码输出的回车后一起输出的。由此可以证明,stdout真的是带有缓存的,直到遇到回车后会输出。stderr却不受影响,正常输出。

 如果需要使stdout正常输出,则加上"\\n"即可!如上面注释的代码!

思考:很多时候我们会用printf打印信息来调试程序,但是如果终端关掉了,那怎么显示printf的调试信息呢?


重定向

1. >

        运行程序时,加上 "> 文件名",即可将代码中标准输出(stdout)的字符串输出到指定文件中。值得注意的是,标准出错(stderr)无法使用此种方式输出到文件。例:

        

#include <unistd.h>
#include <stdio.h>


int main(int argc, char **argv) 
    
    printf("输出重定向:printf...\\n");
    fprintf(stdout, "输出重定向:fprintf(stdout)...\\n");
    fprintf(stderr, "输出重定向:fprintf(stderr)...\\n");
    perror("输出重定向:perror...\\n");

    return 0;

正常运行:   

(最后输出的“:Success”是perror输出的,因为errno全局变量没有存储报错标志,所以输出Success)

输出重定向到文件:

 可以看出,标准输出的已经输出到文件中了。

那么标准出错又该如何输出到文件呢?在运行尾部继续输入“2>&1”即可。

例如:./redirector > test.log 2>&1 

 全都输出到文件中了;但是,它是先输出标准出错,然后再输出标准输出,为什么呢?我觉得应该是缓存所导致的!

另外,使用“>”重定向到文件,会覆盖掉之前的信息,那么如何追加呢?

2. >>

        使用“>>”即可达到追加效果。     ./redirector >> test.log 2>&1   

3. freopen        

FILE *freopen(const char *path, const char *mode, FILE *stream);

path:文件名

mode

            mode                                        描述
                r读方式打开文件,该文件必须存在。
                r+读写方式打开文件,该文件必须存在。
                w写方式打开文件,文件不存在则创建,存在则覆盖。
                w+读写方式打开文件,文件不存在则创建,存在则覆盖。
                a追加方式打开文件,尾部追加,文件不存在则创建。
                a+追加方式打开文件,尾部追加,且可以读取。

stream:取值 stdout 或 stderr.

例:

#include <unistd.h>
#include <stdio.h>


int main(int argc, char **argv) 
    
    FILE *out = freopen("test1.log", "a", stdout);
    //FILE *out = freopen("test1.log", "a", stderr);
    
    printf("输出重定向:printf...\\n");
    fprintf(stdout, "输出重定向:fprintf(stdout)...\\n");
    fprintf(stderr, "输出重定向:fprintf(stderr)...\\n");
    perror("输出重定向:perror...\\n");

    fclose(stdout);
    //fclose(stderr);

    return 0;

 使用stdout打开的文件,就只会将标志输出写入文件;使用stderr就会将标志出错写入文件!

当然我们一定要明白,printf输出到文件,这会引起IO中断,因此执行printf比一般的指令的效率要低很多。


总结:

        平常时我们调试代码或一些小例子代码,可以使用重定向;但对于大型项目,推荐还是使用工程级的日志,例如log4或plog等。

以上是关于Linux 输出重定向 “>”“>>”“freopen”的主要内容,如果未能解决你的问题,请参考以下文章

LINUX 标准错误输出重定向

Linux标准输入输出与重定向详解果断收藏

Linux就该这么学——初识重定向

Linux Bash-重定向

Linux管道符重定向与环境变量

Linux重定向