我正在使用tail -f
读取日志并将数据传递给我的ncurses程序。
tail -f somelog | ./a.out
它工作正常,但是当我按 q 时,程序不会退出,只是挂起直到将一个字节写入正在尾随的文件。使用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;
}
答案 0 :(得分:0)
一旦您的代码调用fgets()
,它将在fgets()
中被阻止,直到更多输入到达 - 或者管道已关闭。
cat somelog | ./a.out
不会发生这种情况,因为正如您所怀疑的那样,cat
并没有等待更多数据写入文件。 cat
不断发送数据然后退出,关闭管道并导致fgets()
返回已缓冲的数据并等待更多数据,如果没有数据则NULL
已被阅读。当tail -f ...
到达文件末尾时,tail -f ...
不会退出并关闭管道 - fgets()
只是等待更多数据写入它正在拖尾的文件,所以你的电话到fgets()
只是坐在那里。
为什么?因为fgets()
在获得换行符或EOF之前不会返回。 Per the Linux man page (assuming you're running on Linux):
EOF
最多只读取一个 size 字符 流 并将它们存储到 s 指向的缓冲区中。阅读停止后newline
或Student
。 ...