为什么阅读STDOUT有效?

时间:2015-12-24 09:03:22

标签: qt unix stdout stdin pty

我遇到了一个奇怪的案例,当在终端中运行程序时,从STDOUT读取工作。问题是,为什么以及如何?让我们从代码开始:

#include <QCoreApplication>
#include <QSocketNotifier>
#include <QDebug>
#include <QByteArray>

#include <unistd.h>
#include <errno.h>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    const int fd_arg = (a.arguments().length()>=2) ? a.arguments().at(1).toInt() : 0;
    qDebug() << "reading from fd" << fd_arg;

    QSocketNotifier n(fd_arg, QSocketNotifier::Read);

    QObject::connect(&n, &QSocketNotifier::activated, [](int fd) {
        char buf[1024];
        auto len = ::read(fd, buf, sizeof buf);
        if (len < 0) { qDebug() << "fd" << fd << "read error:" << errno; qApp->quit(); }
        else if (len == 0)  { qDebug() << "fd" << fd << "done"; qApp->quit(); }
        else {
            QByteArray data(buf, len);
            qDebug() << "fd" << fd << "data" << data.length() << data.trimmed();
        }
    });

    return a.exec();
}

为了方便起见,这里有 qmake .pro文件,如果有人想测试上面的代码:

QT       += core
QT       -= gui
CONFIG += c++11
TARGET = stdoutreadtest
CONFIG   += console
CONFIG   -= app_bundle
TEMPLATE = app
SOURCES += main.cpp

以下是4次执行的输出:

$ ./stdoutreadtest 0 # input from keyboard, ^D ends, works as expected
reading from fd 0
typtyptyp
fd 0 data 10 "typtyptyp"
fd 0 done
$ echo pipe | ./stdoutreadtest 0 # input from pipe, works as expected
reading from fd 0
fd 0 data 5 "pipe"
fd 0 done
$ ./stdoutreadtest 1 # input from keyboard, ^D ends, works!?
reading from fd 1
typtyp
fd 1 data 7 "typtyp"
fd 1 done
$ echo pipe | ./stdoutreadtest 1 # input from pipe, still reads keyboard!?
reading from fd 1
typtyp
fd 1 data 7 "typtyp"
fd 1 done

所以,问题是,发生了什么,为什么上面的最后两个实际上读取了在终端上输入的内容?

我也试过查看导致here的QSocketNotifier来源here,但并没有真正获得任何见解。

1 个答案:

答案 0 :(得分:1)

fd 0,1,2之间没有什么不同,如果不重定向,所有三个fds都指向终端,它们严格是IDENTICAL!

程序通常使用0表示输入,1表示输出,2表示错误,但所有这些都可以有不同的方式。

例如,对于less,普通用法:

prog | less

现在less的输入被重定向到progless无法读取stdin的任何用户输入,因此less如何获得用户输入如向上/向下滚动还是向上/向下翻页?

当然less可以从stdout读取用户输入,这正是less所做的。

所以当你知道bash如何处理这些fds时,你可以明智地使用这些fds。