监视整个目录(甚至是新目录)中的文件(尾-f)


53

我通常会在目录中查看许多日志tail -f directory/*。问题在于,此后将创建一个新日志,该日志将不会显示在屏幕中(因为*已被扩展)。

有没有一种方法可以监视目录中的每个文件,甚至包括进程启动后创建的文件?

Answers:


44

您可以使用... multitail 尾部 多个文件。

multitail -Q 1 'directory/*'

-Q 1 PATTERN表示每1秒检查一次与PATTERN匹配的现有文件或新文件中的新内容。来自所有文件的行显示在同一窗口中,-q而不是使用-Q来拥有单独的窗口。


10

xtail也是一种选择。其手册页将其描述为:

Xtail监视一个或多个文件,并显示自命令调用以来写入文件的所有数据。这对于同时监视多个日志文件非常有用。如果在命令行上输入的条目是目录,则将监视该目录中的所有文件,包括在xtail调用之后创建的文件。如果在命令行上输入的条目不存在,则xtail将监视并监视创建的条目。在显示屏上切换文件时,将显示显示文件路径名的标语。

中断字符(通常为CTRL / C或DEL)将显示正在监视的最新修改文件的列表。发送退出信号(通常为CTRL /反斜杠)以停止xtail。


1
链接已损坏,但我认为与以下内容相同:manpages.ubuntu.com/manpages/zesty/man1/xtail.1.html
edpaez

7

没有关于shell解决方案的想法,但是(假设Linux 1inotify可能是可行的方法。。。请看这个模仿tail -F(使用pyinotify)的示例,也许它可以用作跟踪整个目录的基础。

通常,inotify可以监视目录(引用man 7 inotify

可以在调用inotify_add_watch(2)时在mask中指定以下位,并且可以在read(2)返回的mask字段中返回以下位:

IN_ACCESS         File was accessed (read) (*).
IN_ATTRIB         Metadata changed, e.g., permissions, timestamps,
                    extended attributes, link count (since Linux 2.6.25),
                    UID, GID, etc. (*).
IN_CLOSE_WRITE    File opened for writing was closed (*).
IN_CLOSE_NOWRITE  File not opened for writing was closed (*).
IN_CREATE         File/directory created in watched directory (*).
IN_DELETE         File/directory deleted from watched directory (*).
IN_DELETE_SELF    Watched file/directory was itself deleted.
IN_MODIFY         File was modified (*).
IN_MOVE_SELF      Watched file/directory was itself moved.
IN_MOVED_FROM     File moved out of watched directory (*).
IN_MOVED_TO       File moved into watched directory (*).
IN_OPEN           File was opened (*).

监视的目录,这些事件标有星号(*)以上,就可能出现在目录中的文件,在这种情况下,在返回inotify_event结构名称字段标识目录内的文件的名称。

(...并pyinotify严格遵循这些选项)

1:BSD具有类似的功能kqueue。也许一个跨平台解决方案是可以实现使用GIO(Python绑定)作为抽象层,因为它可以,旁边inotify也可以使用kqueue


2

我写了一本可以满足需要的快速书。

#!/bin/bash
LOG_PATTERN=$1
BASE_DIR=$(dirname $LOG_PATTERN* | head -1)

run_thread (){
    echo Running thread
    tail -F $LOG_PATTERN* &
    THREAD_PID=$!
}

# When someone decides to stop the script - killall children
cleanup () {
    pgrep -P $$ | xargs -i kill {}
    exit
}

trap cleanup SIGHUP SIGINT SIGTERM

if [ $# -ne 1 ]; then
    echo "usage: $0 <directory/pattern without * in the end>"
    exit 1
fi

# Wait for the directory to be created
if [ ! -d $BASE_DIR ] ; then
    echo DIR $BASE_DIR does not exist, waiting for it...
    while [ ! -d $BASE_DIR ] ; do
        sleep 2
    done
    echo DIR $BASE_DIR is now online
fi

# count current number of files
OLD_NUM_OF_FILES=$(ls -l $LOG_PATTERN* 2>/dev/null | wc -l)

# Start Tailing
run_thread

while [ 1 ]; do
    # If files are added - retail
    NUM_FILES=$(ls -l $LOG_PATTERN* 2>/dev/null | wc -l)
    if [ $NUM_FILES -ne $OLD_NUM_OF_FILES ]; then
        OLD_NUM_OF_FILES=$NUM_FILES
        kill $THREAD_PID
        run_thread
    fi
    sleep 1
done

1
实际上,您可以在主循环中省略sleep 1,这样会更快速地获取新文件。但我不喜欢这种繁忙的等待
Itamar

由于sleep这不是繁忙的等待,而是CPU上的软等待,只是轮询。可以将其更改为sleep 0.2s(GNU sleep)或根据需要使其更快地进行更改。
Ned64

2

你也可以用 watch

watch -n0,1 "ls -lrt /directory/ | tail"

次要nitpick:使用命令的输出watch的前x行在备用缓冲区中重画屏幕。在许多没有更改的文件中,如果较早的文件没有更改,则它们tail可能每次都呈现相同的内容,因此您不会看到任何其他条目,因为它们是在“文件”底部“下方”绘制的。屏幕。不过,对于短文件,这很好...
jimbobmcgee

这不能解决原始问题。这仅输出目录列表的最后几行(重复地,始终是最新的-多亏了watch),而不是该目录中所有文件(包括新文件)的最新行。
trs
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.