初识Linux · 重定向和缓冲区(续)
本文是重定向和缓冲区的续篇,所以篇幅并不会很长。本文的主要目标是介绍stderr,对于0 1 即stdin stdout默认打开我们是能够理解的,stderr是什么我们好像并没有使用过?并且本文会加深一下缓冲区的理解和重定向的理解。那么话不多说,进入正题吧。
目录
前言:
本文是重定向和缓冲区的续篇,所以篇幅并不会很长。
本文的主要目标是介绍stderr,对于0 1 即stdin stdout默认打开我们是能够理解的,stderr是什么我们好像并没有使用过?并且本文会加深一下缓冲区的理解和重定向的理解。
那么话不多说,进入正题吧。
加深理解
我们通过一个函数,sprintf来介绍缓冲区,因为sprintf是C语言的函数,而在C语言里面这个函数我们基本上没有使用过,所以学习Linux也有一定程度上介绍了C语言的调用底层的函数。
sprintf的参数是str,后面是正常的printf的参数。
我们可以通过该函数往一个数组里面写入数据:
int main()
{
myFILE *fp = my_fopen(FILE_NAME, "w");
if(fp == NULL) return 1;
const char *str = "hello bit";
int cnt = 10;
char buffer[128];
while(cnt)
{
sprintf(buffer, "%s - %d", str, cnt);
my_fwrite(fp, buffer, strlen(buffer)); // strlen()+1不需要
cnt--;
sleep(1);
my_fflush(fp);
}
my_fclose(fp);
return 0;
}
通过sprintf写入了数据之后,使用我们自己实现的fwrite函数,往fp文件指针指向的缓冲区进行写入,每写入一次,就sleep一秒,然后刷新缓冲区,这样的结果,是将fp指向的缓冲区写入动态的字符串:
这个过程是动态的,但是如果我们将fflush去掉,并且在buffer数组里面不写入\n,我们看到的结果就是log.txt里面是等程序运行完,也就是进程终止之后,强制刷新缓冲区,从而导致的数据刷新出来:
这个点从另一个点,告诉了我们用户级别,也就是语言层面的缓冲区的存在。
而使用函数fllush 转义字符\n都是可以刷新该缓冲区,数据刷新之后,由OS将将数据从内核级别的缓冲区刷新到磁盘里面去。
也算是简单的复习了一下,今天的重点是stderr。
由一个问题引出:
平时我们的使用都是stdin stdout偏多,对于stderr,我们只知道它和错误有关,那么具体的表现是什么呢?我们现在看看。
stderr
我们先使用C++的代码看看:
int main()
{
cout << "Hello Linux! I am cout\n" << endl;
cerr << "Hello Linux! I am cerr\n" << endl;
return 0;
}
为什么这里的cout 和 cerr打印出来的都是一样的呢?
我们使用C语言的stderr stdout试试:
int main()
{
fprintf(stdout,"Hello Linux! I am stdout\n");
fprintf(stderr,"Hello Linux! I am stderr\n");
return 0;
}
此时结果居然还是一样的,难道stderr和stdout就没有区别了吗?
并不是,我们试试重定向?
使用>的时候,发现stdout的数据,存放到了log.txt里面,但是stderr并没有,好像事情有点眉目了?
你想,当用户操作计算机的时候,对于数据的流动是不大清晰的,比如报错,比如输出,甚至比如输入的信息都需要计算机帮我们完成,那么借助谁帮我们完成呢?
其实靠的就是stdin stdout stderror,如果没有报错什么的,stdout stderr的用法基本上是一样的,但是如果有报错信息,我们无法将报错信息重定向到log.txt,这是因为>的真正名称叫做标准输出重定向符,也就是只重定向标准输出,对于标准错误是不会重定向的,所以如果有如下代码:
int main()
{
fprintf(stdout,"Hello Linux! I am stdout\n");
fprintf(stderr,"Hello Linux! I am stderr\n");
fprintf(stderr,"Hello Linux! I am stderr\n");
fprintf(stdout,"Hello Linux! I am stderr\n");
fprintf(stdout,"Hello Linux! I am stderr\n");
fprintf(stderr,"Hello Linux! I am stderr\n");
fprintf(stderr,"Hello Linux! I am stderr\n");
fprintf(stdout,"Hello Linux! I am stderr\n");
fprintf(stderr,"Hello Linux! I am stderr\n");
return 0;
}
也就是stdout stderr的信息混在了一起,人眼分辨出来肯定十分费力,所以使用标准输出重定向的时候,就可以分辨出来了:
对于标准错误就只能打印在显示器上,这个点从另一方面也验证了1 2对应的显示器其实是同一个的结果。
那么如果我想要将1 2的消息都重定向呢?我们就可以:
这个指令稍微有点怪异,但是解释起来是很容易的。进程运行的时候,1重定向到了log.txt里面,2>&1的意思是将1的内容拷贝到2里面,包括文件指针。所以相当于让2的文件指针也指向了1所指向的文件。
此时,完成了2的重定向。
那么,同学们有没有用过,perror呢!!为什么报错的时候我们使用这个打印,而不是使用printf打印!!这里也算是一个call back了,因为perror本质是给2打印,printf是给1打印,虽然结果一样,但是本质不同!!
这是对于stderr的理解。
感谢阅读!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)