如何使用ncurses在窗口中捕获命令行输出?
假设我正在执行像“ls”这样的命令我想在ncurses中设计的特定窗口中打印该输出。我是新来的ncurses.help me.Thanks提前
答案 0 :(得分:1)
我能想到的一件事是使用system()来执行命令,将其输出重定向到临时文件:
system("ls > temp");
然后打开文件temp,读取其内容并在窗口中显示。
不是一个优雅的解决方案,但有效。
答案 1 :(得分:1)
更优雅的解决方案可能是在您的程序中实现重定向。查看dup()和dup2()系统调用(请参阅dup(2)联机帮助页)。那么,你想要做的是(这基本上是由system()调用的shell最终做的事情):
代码段:
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文件处理它们。)
如果用户可以在窗口中执行任意程序,则需要注意ncurses程序 - ncurses将move()和printw()/ addch()/ addstr()命令转换为适当的控制台代码,所以盲目地打印ncurses程序的输出将踩踏程序的输出并忽略你的窗口位置。 GNU屏幕是一个很好的例子来研究如何处理它 - 它实现了一个VT100终端模拟器来捕获ncurses代码,并使用自己的termcap / terminfo条目实现自己的'screen'终端。屏幕的子程序在伪终端中运行。 (xterm和其他终端仿真器执行类似的技巧。)
最后说明:我还没有编译上面的代码。它可能有小错别字,但一般应该是正确的。如果你是mmap(),请确保munmap()。此外,在完成ls输出后,您将要关闭(tmpfile)。 unlink()可能能够在代码中更早出现,或者在close()调用之前 - 取决于你是否希望人们看到你正在玩的输出 - 我通常在mkstemp之后直接放置unlink() ()调用 - 如果tmp目录是磁盘备份的话,这会阻止内核将文件写回磁盘(由于tmpfs,这种情况越来越少)。此外,在取消链接()之后,您将要释放(tmpname)以防止泄漏内存。 strdup()是必要的,因为tmpname由mkstemp()修改。
答案 2 :(得分:-1)
Norman Matloff在第五页的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从数组中输出行。