一个输出内容不同引发的问题

来源:互联网 发布:易语言取中间文本源码 编辑:程序博客网 时间:2024/06/05 07:11

常用的curl、mysql命令行客户端等程序,进行操作后会进行输出,这都是很正常的程序交互,并没有什么问题。但是,在使用他们的过程中,出现了下面这样的问题:

curl 下载一个文件的命令后续没有任何其他管道符操作时,会默认讲文件输出到命令行,但是添加管道符进行后续操作时,就会输出下载文件的进度统计信息,文件内容则不会输出

首先直接下载,输出全部文件内容:

$ curl https://www.baidu.com/404.html<html><head>    <script>        location.replace(location.href.replace("https://","http://"));    </script></head><body>    <noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript></body></html>

然后,使用管道符进行grep操作:

$ curl https://www.baidu.com/404.html | grep "a"  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current                                 Dload  Upload   Total   Spent    Left  Speed100   227  100   227    0     0   4098      0 --:--:-- --:--:-- --:--:--  4127<head>        location.replace(location.href.replace("https://","http://"));</head>    <noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>

这里先输出了下载进度信息,然后进行匹配,输出包含”a”的行。这里的问题就出现了,为什么不使用管道符的时候,下载进度信息没有输出。

这里根据这个现象,推测是curl程序使用stderr输出了下载进度信息,使用stdout输出了文件内容。因此使用管道符的时候接收stdout的文件内容交给grep程序进行匹配,而stderr内容则不交给管道符,因此会先于匹配内容输出;匹配内容是grep程序最后匹配完成之后输出的。

这里的问题又出现了,如果是stderr输出下载进度信息,为什么没有管道符的时候不会输出呢?因此这样推测下去,就只有一种可能,那就是curl程序内部判断了stdout是否通过管道符或者命令行输出。因此,带着这样的困惑,找到了一篇很早的博客,确实有人遇到了同样的问题http://superuser.com/questions/173209/curl-how-to-suppress-strange-output-when-redirecting。

然后查阅了man 手册,发现了isatty函数,这是标准C里面的POXIC协议下的一个函数,用于判断给定文件描述符的文件是否是terminal,函数原型如下:

int isatty(int fd);

基于此,可以使用如下代码在程序中判断stdout是否绑定到终端,从而控制输出不同内容:

#include <unistd.h>int main(int argc, char ** argv) {    if (isatty(1)) {      std::cout << "output when stdout binds to the terminal." << std::endl;    } else {      std::cout << "output not to a terminal binded stdout." << std::endl;    }}

在APUE中查询到了习惯信息,该函数用于一个文件描述符是否绑定于一个终端。并给出了该函数的实现:

#include <termios.h>int isatty(int fd) {  struct termios    ts;  return (tcgetattr(fd, &ts) != -1);}

另外,与此函数相关的还有如下函数:

//返回在给定描述符上打开的终端的文件路径名称char * ttyname(int fd);//返回终端的名称,大多控制终端名字都是 /dev/tty,该函数作用主要是改善向其他操作系统的可移植性char * ctermid(char * str);
0 0
原创粉丝点击