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

常用的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  Speed
100   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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值