我正在使用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