2009-12-24 169 views
1

如何使用ncurses在窗口中捕獲命令行輸出?在ncurses中捕獲命令行輸出

假設我正在執行像「ls」這樣的命令,我想在ncurses中設計的特定窗口中輸出該輸出。我是新來ncurses.help me.Thanks提前

回答

1

一個我能想到的是使用system()來執行命令,它的輸出重定向到一個臨時文件的事情:

system("ls > temp"); 

然後打開文件溫度,讀取其內容並將其顯示在窗口上。

不是一個優雅的解決方案,但工程。

1

更優雅的解決方案可能是在程序中實現重定向。查看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()修改的。

-1

諾曼·馬特夫顯示了他的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