我正在尝试编写一个脚本,用于inotifywatch
监视日志文件中的更改。如果将特定消息写入日志文件,则应该触发某个功能。该脚本目前以这种基本形式存在:
while inotifywait -e modify /var/log/auth.log
do
alert=$(tail -n1 /var/log/auth.log | grep -E -o ".{0,7}password")
if [[ $alert == "Failed password" ]]
then
echo "FAILURE" >> test.log
elif [[ $alert == "cepted password" ]]
then
echo "LOGIN" >> test.log
fi
done
Run Code Online (Sandbox Code Playgroud)
一切正常——直到观察到的日志文件inotifywatch
被旋转。然后它停止工作。我认为这是因为在轮换期间,被监视的文件被重命名,之后不再写入,并且在其位置创建了一个具有旧名称的新文件,该文件inotify
从未被告知首先要监视。
我试图通过从切换inotifywatch
到使用来规避这一点,tail -f
但同样的问题似乎也适用于那里。
现在我意识到这可能可以通过创建一个巨大的if
结构来解决,其中inotifywatch
不仅modify
监视 ,还监视文件创建并重新启动监视进行修改。但是我喜欢保持简单,所以有人知道是否有更简单的方法吗?(拜托,不,我不想使用像 fail2ban 等预制的解决方案——对我来说有趣的部分是自己用简单的工具创建这样的东西。)
inotify
用于通过索引节点而不是名称来监视目录中的文件。当文件被轮换时,它的内容不再改变(除了一小段时间,直到守护进程被重新加载以便它们使用新创建的日志文件)
AFAIK,tail -f
使用 inotify 系统,所以它无济于事。但是,如果您有一个可行的解决方案,tail -f
则使用tail --follow=name
(或tail -F
)如果您的版本支持tail
(POSIX tail 不支持此功能)。tail
然后将监视由其文件名标识的文件。以下是手册页的摘录:
使用--follow (-f),tail 默认跟在文件描述符之后,这意味着即使一个tail'ed 的文件被重命名,tail 也会con?继续追踪它的结束。当您确实想要跟踪文件的实际名称而不是文件描述符(例如日志轮换)时,这种默认行为是不可取的。在这种情况下使用 --follow=name 。这会导致 tail 以适应重命名、删除和创建的方式跟踪命名文件。
[更新]
使用示例:
tail -n0 -F my_file.log \
| while read -r log_line; do
do_something_with "$log_line"
done
Run Code Online (Sandbox Code Playgroud)
因为管道的原因,while循环是在子进程中执行的,如果你想在循环外修改变量,可能会给你带来麻烦。如果您使用bash
,您可能希望使用这种替代语法,它不会产生这种不良影响(但可读性较差):
while read -r log_line; do
do_something_with "$log_line"
done < <(tail -n0 -F my_file.log)
Run Code Online (Sandbox Code Playgroud)