Answers:
一个简单的方法将是awk。
tail -f /path/to/serverLog | awk '
/Printer is on fire!/ { system("shutdown -h now") }
/new USB high speed/ { system("echo \"New USB\" | mail admin") }'
是的,这两个都是来自内核日志的真实消息。Perl可能会更优雅一些,也可以代替尾部。如果使用perl,它将看起来像这样:
open(my $fd, "<", "/path/to/serverLog") or die "Can't open log";
while(1) {
if(eof $fd) {
sleep 1;
$fd->clearerr;
next;
}
my $line = <$fd>;
chomp($line);
if($line =~ /Printer is on fire!/) {
system("shutdown -h now");
} elsif($line =~ /new USB high speed/) {
system("echo \"New USB\" | mail admin");
}
}
awk
短而易行的解决方案。但是,如果我要运行的命令带有引号,则可能有点麻烦,是否有替代方法,可能使用管道和复合命令,它们也允许使用简短的单线解决方案,但不需要传递结果命令作为字符串?
system()
命令内部使用。
tail -f /path/to/serverLog | grep "server is up" | head -1 && do_some_command
tail -n 0 -f /path/to/serverLog
它将读取文件的最后0行,然后等待更多行打印。
如果您只是在寻找一种可能性,并且希望将大部分时间留在shell中而不是使用awk
或perl
,则可以执行以下操作:
tail -F /path/to/serverLog |
grep --line-buffered 'server is up' |
while read ; do my_command ; done
...该文件将在my_command
每次“ 服务器启动 ” 时运行。对于多种可能性,也许你可以删除grep
,而使用一个case
内while
。
大写-F
字母告诉tail
监视日志文件是否被轮换;例如,如果当前文件被重命名并且另一个具有相同名称的文件被替换,tail
它将切换到新文件。
该--line-buffered
选项告诉grep
每行之后刷新其缓冲区;否则,my_command
可能无法及时到达(假设原木具有合理尺寸的线)。
--line-buffered
选项grep
,否则请确保该选项刷新行之间的输出:否则,它只会挂起,并且my_command
永远不会到达。如果愿意ack
,它带有一个--flush
标志;如果愿意ag
,可以尝试用stdbuf
。stackoverflow.com/questions/28982518/…–
do exit ;
。看起来工作正常,但是拖尾从未完成,我们的脚本也从未移至下一行。有没有办法阻止该do
节的尾巴?
这个问题似乎已经得到回答,但是我认为有更好的解决方案。
相反tail | whatever
,我认为您真正想要的是swatch
。Swatch是一个明确设计的程序,用于执行您的要求,查看日志文件并根据日志行执行操作。使用tail|foo
将需要您有一个正在运行的终端来执行此操作。另一方面,Swatch作为守护程序运行,它将始终在监视您的日志。Swatch在所有Linux发行版中都可用,
我鼓励您尝试一下。尽管您可以用螺丝刀的背面敲打指甲,但这并不意味着您应该这样做。
我可以在这里找到有关样本的30秒最佳教程:http : //www.campin.net/newlogcheck.html
让我们看看它可能多么简单和可读:
mylog() {
echo >>/path/to/myscriptLog "$@"
}
while read line;do
case "$line" in
*"Printer on fire"* )
mylog Halting immediately
shutdown -h now
;;
*DHCPREQUEST* )
[[ "$line" =~ DHCPREQUEST\ for\ ([^\ ]*)\ ]]
mylog Incomming or refresh for ${BASH_REMATCH[1]}
$HOME/SomethingWithNewClient ${BASH_REMATCH[1]}
;;
* )
mylog "untrapped entry: $line"
;;
esac
done < <(tail -f /path/to/logfile)
虽然您不使用bash regex
,但是可以保持很快的速度!
但是对于高负载服务器,并且我喜欢sed
它,因为它非常快且具有很好的可伸缩性,因此我经常使用以下命令:
while read event target lost ; do
case $event in
NEW )
ip2int $target intTarget
((count[intTarget]++))
...
esac
done < <(tail -f /path/logfile | sed -une '
s/^.*New incom.*from ip \([0-9.]\+\) .*$/NEW \1/p;
s/^.*Auth.*ip \([0-9.]\+\) failed./FAIL \1/p;
...
')
这也是我也开始这样做的方式,但是变得越来越复杂。需要注意的几件事:
我使用一些类似的方法:
RELEASE=/tmp/${RANDOM}$$
(
trap 'false' 1
trap "rm -f ${RELEASE}" 0
while ! [ -s ${RELEASE} ]; do sleep 3; done
# You can put code here if you want to do something
# once the grep succeeds.
) & wait_pid=$!
tail --pid=${wait_pid} -F /path/to/serverLog \
| sed "1,10d" \
| grep "server is up" > ${RELEASE}
保持tail
打开状态直到${RELEASE}
文件包含数据为止。
一旦grep
成功的话:
${RELEASE}
这将${wait_pid}
过程以tail
注意:sed
可以更复杂地实际确定tail
启动时将产生的行数并删除该数目。但通常是10。
tail -F
处理日志旋转-即my.log
满,并移动到my.log.1
和你的进程创建一个新的my.log