如何将GNU Readline远离Stdout

时间:2019-03-25 19:06:10

标签: c stdin gnu readline getline

所以我想制作一个程序,该程序通过重定向或交互式输入接受stdin的输入。 getline可以实现重定向读取,但是我想为交互式输入提供readline的所有出色功能。该程序的目的是通过一种语言来操纵文本并将结果输出到stdout(类似于sed所做的事情)。问题是,我无法对my_prog > output.txt进行readline,因为在readline中输入了什么内容,readline的输出都进入了该文件,我什至看不到它。目前,我有一种解决方法,我只是使用readlinestderr的输出发送到rl_outstream。这给了我我要寻找的行为,但是当可能有一个更简单的解决方案时,感觉就像是一个hack。我正在寻找的一个很好的例子是python的功能。

python > output.txt
>>> print 'hello'
>>> exit()
cat output.txt
hello

这是一些代码来演示我在做什么...

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

#include "readline/readline.h"

int main(int argc, char** argv)
{
    char* from_stdin = malloc(512);
    char* line = NULL;

    rl_outstream = stderr;

    if(isatty(STDIN_FILENO)) {
        do {
            line = readline("");
            if(line) {
                strcat(from_stdin, line);
                strcat(from_stdin, "\n");
            } else {
                break;
            }
        } while(1);
    } else {
        size_t n = 0;
        while(getline(&line, &n, stdin) != -1)
            strcat(from_stdin, line);
    }
    puts(from_stdin);
}

修补可接受的解决方案:

--rl_outstream = stderr;
++FILE* more_hacky = fopen("/dev/tty", "w");
++rl_outstream = more_hacky;

我同意这种做法更加骇人听闻。我可能会保留我的代码,但是如果我选择的话,这会使stderr更“纯净”,以免出现错误。

1 个答案:

答案 0 :(得分:2)

对于它的价值,CPython 确实使用STDERR_FILENO作为Readline iff !isatty(STDOUT_FILENO)的输出文件描述符,您可以使用strace进行验证,并且一样。

我们无需重定向

% strace -o strace.out python3 && grep '>>>' strace.out
Python 3.6.7 (default, Oct 22 2018, 11:32:17) 
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> ^D
write(1, ">>> ", 4)                     = 4

并带有重定向

% strace -o strace.out python3 > python.out && grep '>>>' strace.out
Python 3.6.7 (default, Oct 22 2018, 11:32:17) 
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> ^D
write(2, ">>> ", 4)                     = 4

另一种选择是为输出流打开/dev/tty,但我觉得 会更加(而不是更少)骇客。