jon*_*rry 60 logs shell-script tail text-processing
我有一个服务器日志,它在服务器启动时将特定的文本行输出到其日志文件中。我想在服务器启动后执行命令,因此执行以下操作:
tail -f /path/to/serverLog | grep "server is up" ...(now, e.g., wget on server)?
Run Code Online (Sandbox Code Playgroud)
做这个的最好方式是什么?
pen*_*359 38
一个简单的方法是 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") }'
Run Code Online (Sandbox Code Playgroud)
是的,这两个都是来自内核日志的真实消息。Perl 使用起来可能更优雅一些,并且还可以取代对 tail 的需求。如果使用 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");
}
}
Run Code Online (Sandbox Code Playgroud)
Jan*_*der 27
如果您只是在寻找一种可能性并且希望大部分时间留在外壳中而不是使用awk
or perl
,您可以执行以下操作:
tail -F /path/to/serverLog |
grep --line-buffered 'server is up' |
while read ; do my_command ; done
Run Code Online (Sandbox Code Playgroud)
...my_command
每次“ server is up ”出现在日志文件中时都会运行。对于多种可能性,您可以删除grep
,而是case
在while
.
资本-F
告诉tail
观察要轮换的日志文件;即,如果当前文件被重命名并且另一个同名文件取而代之,tail
则将切换到新文件。
该--line-buffered
选项告诉grep
在每行之后刷新其缓冲区;否则,my_command
可能无法及时到达(假设日志具有合理大小的行)。
Sla*_*hin 11
奇怪的是,没有人提到multitail
具有开箱即用功能的实用程序。使用示例之一:
显示 ping 命令的输出,如果显示超时,则向当前登录的所有用户发送消息
multitail -ex timeout "echo timeout | wall" -l "ping 192.168.0.1"
Run Code Online (Sandbox Code Playgroud)
又见另一个实例的multitail
使用。
让我们看看它有多简单和易读:
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)
Run Code Online (Sandbox Code Playgroud)
虽然您不使用 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;
...
')
Run Code Online (Sandbox Code Playgroud)
这就是我开始这样做的方式,但已经变得更加复杂。需要关注的几件事:
我使用的东西是这样的:
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}
Run Code Online (Sandbox Code Playgroud)
它的工作原理是保持tail
打开直到${RELEASE}
文件包含数据。
一旦grep
成功:
${RELEASE}
这将${wait_pid}
进程tail
注意:sed
实际确定tail
启动时将产生的行数并删除该数字可能会更复杂。但一般情况下,它是 10。