在ncurses中捕获命令行输出
如何使用ncurses在窗口中捕获命令行输出?在ncurses中捕获命令行输出
假设我正在执行像“ls”这样的命令,我想在ncurses中设计的特定窗口中输出该输出。我是新来ncurses.help me.Thanks提前
一个我能想到的是使用system()来执行命令,它的输出重定向到一个临时文件的事情:
system("ls > temp");
然后打开文件温度,读取其内容并将其显示在窗口上。
不是一个优雅的解决方案,但工程。
更优雅的解决方案可能是在程序中实现重定向。查看dup()和dup2()系统调用(请参阅dup(2)联机帮助页)。所以,你会想要做的是(实际上,这就是由系统调用()的壳最后也做):
代码段:
char *tmpname;
int tmpfile;
pid_t pid;
int r;
tmpname = strdup("/tmp/ls_out_XXXXXX");
assert(tmpname);
tmpfile = mkstemp(tmpname);
assert(tmpfile >= 0);
pid = fork();
if (pid == 0) { // child process
r = dup2(STDOUT_FILENO, tmpfile);
assert(r == STDOUT_FILENO);
execl("/bin/ls", "ls", NULL);
assert(0);
} else if (pid > 0) { // parent
waitpid(pid, &r, 0);
/* you can mmap(2) tmpfile here, and read from it like it was a memory buffer, or
* read and write as normal, mmap() is nicer--the kernel handles the buffering
* and other memory management hassles.
*/
} else {
/* fork() failed, bail violently for this example, you can handle differently as
* appropriately.
*/
assert(0);
}
// tmpfile is the file descriptor for the ls output.
unlink(tmpname); // file stays around until close(2) for this process only
更多挑剔的程序(那些关心他们有一个用于输入和输出的终端),您将需要查看伪ttys,请参阅pty(7)手册页。 (或google'pty')。如果你想让ls做它的多列漂亮打印(例如,ls会检测到它正在输出到一个文件,并且将一个文件名写入一行),这将是必需的。如果你想让ls去做你需要一个pty。另外,你应该能够在fork()之后设置$ LINES和$ COLUMNS环境变量,以便让ls能够很好地打印到你的窗口大小 - 同样,假设你正在使用一个pty,最重要的变化是你可以删除tmpfile = mkstemp(...);并用pty打开逻辑替换它和周围的逻辑,并且扩展dup2()调用来处理stdin和stderr ,dup2()从它们的pty文件句柄)。 ()和printw()/ addch()/ addstr()命令转换到相应的控制台中(如果用户可以在窗口中执行任意程序,则需要小心ncurses程序)代码,所以一味打印ncurses程序的输出会压制你的程序输出并忽略你的窗口位置。 GNU屏幕是研究如何处理这个问题的一个很好的例子 - 它实现了一个VT100终端仿真器来捕获ncurses代码,并使用自己的termcap/terminfo条目实现自己的'screen'终端。屏幕的子程序在伪终端中运行。 (xterm和其他终端仿真器执行类似的技巧。)
最后说明:我没有编译上面的代码。它可能有小的错别字,但应该大致正确。如果您使用mmap(),请确保使用munmap()。另外,在完成ls输出后,您需要关闭(tmpfile)。 unlink()在代码中或者在close()调用之前可能会早得多 - 取决于你是否希望人们看到你的输出 - 我通常将unlink()直接放在mkstemp之后()调用 - 如果tmp目录是磁盘备份的,这可以防止内核将文件写回磁盘(由于tmpfs,这是不太常见的)。另外,在取消链接()以防止内存泄漏之后,您需要释放(tmpname)。 strdup()是必需的,因为tmpname是由mkstemp()修改的。
诺曼·马特夫显示了他的Introduction to the Unix Curses Library第五页的方式:
// runs "ps ax" and stores the output in cmdoutlines
runpsax()
{ FILE* p; char ln[MAXCOL]; int row,tmp;
p = popen("ps ax","r"); // open Unix pipe (enables one program to read
// output of another as if it were a file)
for (row = 0; row < MAXROW; row++) {
tmp = fgets(ln,MAXCOL,p); // read one line from the pipe
if (tmp == NULL) break; // if end of pipe, break
// don’t want stored line to exceed width of screen, which the
// curses library provides to us in the variable COLS, so truncate
// to at most COLS characters
strncpy(cmdoutlines[row],ln,COLS);
// remove EOL character
cmdoutlines[row][MAXCOL-1] = 0;
}
ncmdlines = row;
close(p); // close pipe
}
...
他然后叫mvaddstr(...)
通过ncurses的熄从数组行。
是的示例是curses示例应用程序的一部分,但显示的代码与curses无关。这只是常规的输出重定向 – sehe 2016-12-14 20:04:53