如何使 ncurses 程序与其他 linux 实用程序一起工作?
how to make ncurses program working with other linux utils?
假设我有一个 ncurses 程序,它在 curses 屏幕上做一些工作,最后打印一些东西到 stdout
。调用此程序 c.c
,编译为 a.out
.
我预计 cat $(./a.out)
首先启动 ncurses,经过一些操作后,a.out
退出并打印 c.c
到 stdout
,由 cat
读取, 从而打印文件 c.c
.
的内容
#include <stdio.h>
#include <ncurses.h>
int main() {
initscr();
noecho();
cbreak();
printw("hello world");
refresh();
getch();
endwin();
fprintf(stdout, "c.c");
return 0;
}
我也希望 ./a.out | xargs vim
、ls | ./a.out | xargs less
能正常工作。
但是当我输入 ./a.out | xargs vim
时,hello world
永远不会出现。命令好像没有按顺序执行,vim打不开c.c
.
使 ncurses 程序与其他 linux 实用程序一起工作的正确方法是什么?
ncurses
通过将一堆 ansi 转义符写入 stdout 来工作,终端将对其进行解释。您可以 运行 ./a.out > file
然后检查文件以查看您 实际上 正在写什么。程序混淆的原因将立即显而易见:
$ cat -vE file
^[(B^[)0^[[?1049h^[[1;24r^[[m^O^[[4l^[[H^[[Jhello world^[[24;1H^[[?1049l^M^[[?1l^[>c.c
正确的做法是当您检测到 stdout 不是终端时跳过所有 graphical/textual UI 部分,即它被程序而不是用户使用:
#include <unistd.h>
#include <stdio.h>
#include <ncurses.h>
int main() {
if(isatty(1)) {
// Output is a terminal. Show stuff to the user.
initscr();
noecho();
cbreak();
printw("hello world");
refresh();
getch();
endwin();
} else {
// Output is consumed by a program.
// Skip UI.
}
fprintf(stdout, "c.c");
return 0;
}
这是典型的 Unix 行为。
如果您不想强制显示 UI,您可以 。
管道使用标准输出 (stdout) 和标准输入 (stdin)。
最简单的方法 - 而不是使用 initscr
,它将输出初始化为使用 标准输出 ,使用 newterm
,它允许您选择文件描述符,例如,
newterm(NULL, stderr, stdin);
而不是
initscr();
与
(几乎)相同
newterm(NULL, stdout, stdin);
顺便说一下,当你包含<ncurses.h>
(或<curses.h>
)时,就不需要包含<stdio.h>
.
如果你想在管道的中间使用你的程序,那就更复杂了:你必须耗尽标准输入并打开实际的终端设备。但这是另一个问题(并且已经得到回答)。
延伸阅读:
假设我有一个 ncurses 程序,它在 curses 屏幕上做一些工作,最后打印一些东西到 stdout
。调用此程序 c.c
,编译为 a.out
.
我预计 cat $(./a.out)
首先启动 ncurses,经过一些操作后,a.out
退出并打印 c.c
到 stdout
,由 cat
读取, 从而打印文件 c.c
.
#include <stdio.h>
#include <ncurses.h>
int main() {
initscr();
noecho();
cbreak();
printw("hello world");
refresh();
getch();
endwin();
fprintf(stdout, "c.c");
return 0;
}
我也希望 ./a.out | xargs vim
、ls | ./a.out | xargs less
能正常工作。
但是当我输入 ./a.out | xargs vim
时,hello world
永远不会出现。命令好像没有按顺序执行,vim打不开c.c
.
使 ncurses 程序与其他 linux 实用程序一起工作的正确方法是什么?
ncurses
通过将一堆 ansi 转义符写入 stdout 来工作,终端将对其进行解释。您可以 运行 ./a.out > file
然后检查文件以查看您 实际上 正在写什么。程序混淆的原因将立即显而易见:
$ cat -vE file
^[(B^[)0^[[?1049h^[[1;24r^[[m^O^[[4l^[[H^[[Jhello world^[[24;1H^[[?1049l^M^[[?1l^[>c.c
正确的做法是当您检测到 stdout 不是终端时跳过所有 graphical/textual UI 部分,即它被程序而不是用户使用:
#include <unistd.h>
#include <stdio.h>
#include <ncurses.h>
int main() {
if(isatty(1)) {
// Output is a terminal. Show stuff to the user.
initscr();
noecho();
cbreak();
printw("hello world");
refresh();
getch();
endwin();
} else {
// Output is consumed by a program.
// Skip UI.
}
fprintf(stdout, "c.c");
return 0;
}
这是典型的 Unix 行为。
如果您不想强制显示 UI,您可以
管道使用标准输出 (stdout) 和标准输入 (stdin)。
最简单的方法 - 而不是使用 initscr
,它将输出初始化为使用 标准输出 ,使用 newterm
,它允许您选择文件描述符,例如,
newterm(NULL, stderr, stdin);
而不是
initscr();
与
(几乎)相同newterm(NULL, stdout, stdin);
顺便说一下,当你包含<ncurses.h>
(或<curses.h>
)时,就不需要包含<stdio.h>
.
如果你想在管道的中间使用你的程序,那就更复杂了:你必须耗尽标准输入并打开实际的终端设备。但这是另一个问题(并且已经得到回答)。
延伸阅读: