尾巴-f新文件

有没有办法做这样的事情:

tail -f logs/ 

并使stdout更新每一行添加到日志中已经存在的每个文件/ 每个文件将创build日志/命令发出后?

感谢所有的支持,但既然也不是多变,也不是尾巴-F也不看尾巴似乎帮助我需要什么,我用C开发了一个小的解决scheme。我在这里发布代码,因为也许有人会发现它有用。 (缺less支票和我知道的一些弱点,但到目前为止已经足够了)

 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/inotify.h> #include <sys/stat.h> #include <signal.h> #include <dirent.h> #include <linux/limits.h> #define CHAR_BACK 500 // * File handler structure struct file_followed { long last_position; char filename[NAME_MAX]; struct file_followed * next; }; struct file_followed * file_list = NULL; // * To quit peacefully int cycle = 1; void stopCycle(int u) { cycle = 0; } // * Last tailed filename char last_tailed[NAME_MAX]; void fileAdd(char * file) { struct file_followed ** list = &file_list; struct stat statdesc; if(stat(file, &statdesc) || !S_ISREG(statdesc.st_mode)) { return; } while(*list) { list = &((*list)->next); } *list = malloc(sizeof(struct file_followed)); (*list)->last_position = -1; strcpy((*list)->filename, file); (*list)->next = NULL; } int fileTail(struct file_followed * item) { int ret = 0; FILE * fp = fopen(item->filename, "r"); fseek(fp, 0, SEEK_END); long end_position = ftell(fp); if( end_position != item->last_position ) { if(strcmp(item->filename, last_tailed)) { strcpy(last_tailed, item->filename); printf("\n** %s **:\n", item->filename); } int start_position = item->last_position == -1 || item->last_position > end_position ? (end_position-CHAR_BACK > 0 ? end_position-CHAR_BACK : 0) : item->last_position; fseek(fp, start_position, SEEK_SET); int len = end_position - start_position; char * buf = malloc(len+1); fread(buf, len, 1, fp); buf[len] = '\0'; printf("%s%s", len == CHAR_BACK ? "[...]" : "", buf); free(buf); item->last_position = end_position; ret = 1; } fclose(fp); return ret; } void fileRem(char * file) { struct file_followed ** list = &file_list; while(*list && strcmp((*list)->filename, file)) { list = &((*list)->next); } if(*list) { struct file_followed * todel = *list; *list = (*list)->next; free(todel); } } int main(int argc, char ** argv) { struct dirent **namelist; struct stat statdesc; struct timeval tv; fd_set set; int fd; int wd; int r; // * Help if(stat(argv[1], &statdesc) || !S_ISDIR(statdesc.st_mode)) { printf("[usage] %s dir-to-monitor\n", argv[0]); exit(EXIT_FAILURE); } // * Init chdir(argv[1]); memset(last_tailed, 0, sizeof(last_tailed)); signal(SIGINT, stopCycle); signal(SIGTERM, stopCycle); // * Inotify if( (fd = inotify_init()) < 0) { perror("inotify_init"); } if( (wd = inotify_add_watch( fd, ".", IN_CREATE | IN_DELETE ) < 0)) { perror("inotify_add_watch"); } // * File add recursively on dirscan if( (r = scandir(".", &namelist, 0, alphasort)) < 0) { perror("scandir"); } while (r--) { fileAdd(namelist[r]->d_name); free(namelist[r]); } free(namelist); // * Neverending cycle while(cycle) { // * Select on inotify FD_ZERO(&set); FD_SET(fd, &set); tv.tv_sec = 0; tv.tv_usec = 1000; if( (r = select(fd+1, &set, NULL, NULL, &tv)) == -1) { perror("select"); } // * New add or del on inotify if(r) { struct inotify_event * event; char buf[1024]; if(read(fd, buf, 1024) <= 0) { perror("read"); } event = (struct inotify_event *) buf; if(event->mask & IN_CREATE) { fileAdd(event->name); } else if(event->mask & IN_DELETE) { fileRem(event->name); } } // * Check for new tails struct file_followed * list = file_list; int tailers = 0; while(list) { tailers += fileTail(list); list = list->next; } if(!tailers) { usleep(500000); } } // * Stop inotify inotify_rm_watch( fd, wd ); close(fd); return EXIT_SUCCESS; } 

我对https://serverfault.com/a/542580/203373进行了修改,在我的系统上修复了一些编译错误(使用Ubuntu linux)。 我添加了强制转换(struct file_followed*)(char*) ,并在添加监视列表中添加了IN_MODIFY以监视对当前文件的修改。 添加了这一行:

if(event->mask & IN_MODIFY) { fileMod(event->name, file_list); }

fileMod函数

 void fileMod(char* fileName, struct file_followed* file_list) 

检查修改后的文件是否被截断,如果已更新item->last_position = -1 ,则打印出来以便重新打印该文件。

 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/inotify.h> #include <sys/stat.h> #include <signal.h> #include <dirent.h> #include <linux/limits.h> #define CHAR_BACK 500 // * File handler structure struct file_followed { long last_position; char filename[NAME_MAX]; struct file_followed * next; }; struct file_followed * file_list = NULL; // * To quit peacefully int cycle = 1; void stopCycle(int u) { cycle = 0; } // * Last tailed filename char last_tailed[NAME_MAX]; void fileAdd(char * file) { struct file_followed ** list = &file_list; struct stat statdesc; if(stat(file, &statdesc) || !S_ISREG(statdesc.st_mode)) { return; } while(*list) { list = &((*list)->next); } *list = (struct file_followed*)malloc(sizeof(struct file_followed)); (*list)->last_position = -1; strcpy((*list)->filename, file); (*list)->next = NULL; } void fileMod(char* fileName, struct file_followed* file_list) { struct file_followed* item = file_list; while(item) { if(strcmp(item->filename, fileName) == 0) { FILE* fp = fopen(item->filename, "r"); fseek(fp, 0, SEEK_END); long end_position = ftell(fp); fclose(fp); if (end_position <= item->last_position) { printf("\n** %s truncated **\n", fileName); item->last_position = -1; } usleep(100); return; } item = item->next; } } int fileTail(struct file_followed * item) { int ret = 0; FILE * fp = fopen(item->filename, "r"); fseek(fp, 0, SEEK_END); long end_position = ftell(fp); if( end_position != item->last_position ) { if(strcmp(item->filename, last_tailed)) { strcpy(last_tailed, item->filename); printf("\n** %s **:\n", item->filename); } int start_position = item->last_position == -1 || item->last_position > end_position ? (end_position-CHAR_BACK > 0 ? end_position-CHAR_BACK : 0) : item->last_position; fseek(fp, start_position, SEEK_SET); int len = end_position - start_position; char * buf = (char*)malloc(len+1); fread(buf, len, 1, fp); buf[len] = '\0'; printf("%s%s", len == CHAR_BACK ? "[...]" : "", buf); free(buf); item->last_position = end_position; ret = 1; } fclose(fp); return ret; } void fileRem(char * file) { struct file_followed ** list = &file_list; while(*list && strcmp((*list)->filename, file)) { list = &((*list)->next); } if(*list) { struct file_followed * todel = *list; *list = (*list)->next; free(todel); } } int main(int argc, char ** argv) { struct dirent **namelist; struct stat statdesc; struct timeval tv; fd_set set; int fd; int wd; int r; // * Help if(stat(argv[1], &statdesc) || !S_ISDIR(statdesc.st_mode)) { printf("[usage] %s dir-to-monitor\n", argv[0]); exit(EXIT_FAILURE); } // * Init chdir(argv[1]); memset(last_tailed, 0, sizeof(last_tailed)); signal(SIGINT, stopCycle); signal(SIGTERM, stopCycle); // * Inotify if( (fd = inotify_init()) < 0) { perror("inotify_init"); } if( (wd = inotify_add_watch( fd, ".", IN_CREATE | IN_MODIFY |IN_DELETE ) < 0)) { perror("inotify_add_watch"); } // * File add recursively on dirscan if( (r = scandir(".", &namelist, 0, alphasort)) < 0) { perror("scandir"); } while (r--) { fileAdd(namelist[r]->d_name); free(namelist[r]); } free(namelist); // * Neverending cycle while(cycle) { // * Select on inotify FD_ZERO(&set); FD_SET(fd, &set); tv.tv_sec = 0; tv.tv_usec = 1000; if( (r = select(fd+1, &set, NULL, NULL, &tv)) == -1) { perror("select"); } // * New add or del on inotify if(r) { struct inotify_event * event; char buf[1024]; if(read(fd, buf, 1024) <= 0) { perror("read"); } event = (struct inotify_event *) buf; if(event->mask & IN_MODIFY) { fileMod(event->name, file_list);} else if(event->mask & IN_CREATE) { fileAdd(event->name); } else if(event->mask & IN_DELETE) { fileRem(event->name); } } // * Check for new tails struct file_followed * list = file_list; int tailers = 0; while(list) { tailers += fileTail(list); list = list->next; } if(!tailers) { usleep(500000); } } // * Stop inotify inotify_rm_watch( fd, wd ); close(fd); return EXIT_SUCCESS; } 

我不认为只有使用tail ,但你应该能够使用tail一起watch同样的效果。 唯一的危险就是确保你没有创build一个目录而不是一个新的文件,这可以通过确保你使用一个合适的shell传递给tail来缓解。 例如: watch -n 2 tail *.log

你可以使用: tail -F logs/*

奖励小贴士:检查多发,这是一个伟大的小命令。

例如 :将所有apache日志文件(* access_log / * error_log)合并到一个窗口中:

 multitail -cS apache --mergeall /var/log/apache2/*access_log --no-mergeall \ -cS apache_error --mergeall /var/log/apache2/*error_log --no-mergeall 

在合并2时显示5个日志文件,并将它们放在两列中,只有一列在左列:

 multitail -s 2 -sn 1,3 /var/log/apache/access.log -I /var/log/apache/error.log \ /var/log/messages /var/log/mail.log /var/log/syslog 

你也许可以使用像multitail这样的东西来同时multitail多个文件。 如果将其与-F选项结合使用(如果文件不存在,请重试,然后重新启动)。