我正在使用tail -f
讀取日誌並將數據傳輸到我的ncurses程序。爲什麼fgets在程序關閉並且數據從tail -f傳送時掛起?
tail -f somelog | ./a.out
當我按下q它的工作原理,除了罰款,程序不退出,它只是掛起直到一個字節寫入文件是tail'd。這在使用cat somelog | ./a.out
時不會發生,我想這是因爲沒有被遵循。
它看起來像行while(fgets(buf, 1024, input)
是造成這個問題。任何想法爲什麼以及如何修復它?由於
// gcc app.c -lncurses
// tail -f logfile | ./a.out
#include <stdio.h>
#include <ncurses.h>
#include <fcntl.h>
#include <string.h>
void print_status(WINDOW * win, const char *str) {
init_pair(1, COLOR_RED, COLOR_WHITE);
clear();
mvwhline(win, 0, 0, ' ', COLS);
mvwaddnstr(win, 0, 0, str, COLS);
wrefresh(win);
}
void print_line(WINDOW * win, const char *str, int *i) {
init_pair(2, COLOR_RED, COLOR_BLACK);
if (*i > LINES - 2) {
*i = 1;
wclear(win);
}
mvwprintw(win, (*i)++, 0, str);
wrefresh(win);
}
int main() {
WINDOW *menu_win, *wi;
int i = 1, q = 1, fd1, fd2, is_atty = 1;
char buf[1024];
initscr();
clear();
halfdelay(5);
menu_win = newwin(1, COLS, 0, 0);
wi = newwin(LINES - 1, COLS, 1, 0);
keypad(menu_win, TRUE);
FILE *input = stdin;
if(!isatty(fileno(stdin))) {
is_atty = 0;
fd1 = open("/dev/tty", O_RDONLY);
fd2 = dup(fileno(stdin));
input = fdopen(fd2, "r");
freopen("/dev/tty", "r", stdin);
if(fileno(stdin) != 0) /* from ncurses dialog */
(void)dup2(fileno(stdin), 0);
close(fd1);
int flags = fcntl(fd2, F_GETFL);
// non-blocking fgets so getch works fine
fcntl(fd2, F_SETFL, flags|O_NONBLOCK);
}
print_status(menu_win, "Use arrow keys to go up and down");
while(q) {
switch(wgetch(menu_win)) {
case KEY_UP:
print_status(menu_win, "Moved up");
break;
case KEY_DOWN:
print_status(menu_win, "Moved down");
break;
case 'q':
q = 0;
break;
default:
if(is_atty) break;
while(fgets(buf, 1024, input) != NULL) {
print_line(wi, buf, &i);
}
break;
}
}
fclose(input);
close(fd2);
endwin();
return 0;
}
'cat'發送'EOF',而'tail -f'沒有,它只是保持管道打開。如果是「尾巴-100」,它將表現得像貓一樣。但是,當您按'q'時,您標識的行不會被調用。你沒有關閉'input',但你沒有關閉'fd2'。 – alvits
@alvits謝謝我編輯了這個問題並添加了'close(fd2)'。 – user1024718
'default:'情況只有在您按任意鍵時纔會執行。當你按下'q'時,它執行'case'q':',隨後導致'while'循環終止。這不是導致它阻塞的'fgets()'。當它到達'return 0;'時,管道仍然打開。運行'tail -f somelog | strace。/ a.out'。看看你的代碼是否關閉管道。當它收到一個SIGPIPE時,tail會終止。請記住,你有幾個管道副本。在'case'q'中打印一些東西:'block。這將幫助您排除故障。 – alvits