在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 &gt= 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的熄从数组行。

+0

是的示例是curses示例应用程序的一部分,但显示的代码与curses无关。这只是常规的输出重定向 – sehe 2016-12-14 20:04:53