サーバーログがあり、サーバーが起動すると、ログファイルに特定のテキスト行が出力されます。サーバーの起動後にコマンドを実行したいので、次のようにします。
tail -f /path/to/serverLog | grep "server is up" ...(now, e.g., wget on server)?
これを行う最良の方法は何ですか?
答え1
簡単な方法は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");
}
}
答え2
1つの可能性のみを探していて、awk
orを使用するのではなく、ほとんどの場合シェルに滞在したい場合は、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
時間に到着できない可能性があります(ログに適切なサイズの行があると仮定)。
答え3
奇妙なことに、multitail
この機能をすぐに使用できるユーティリティについて言及した人はいません。使用例の1つ:
pingコマンドの出力を表示し、タイムアウトが表示されたら、現在ログインしているすべてのユーザーにメッセージを送信します。
multitail -ex timeout "echo timeout | wall" -l "ping 192.168.0.1"
また、見ることができます他の例使用法multitail
。
答え4
強く打つ仕事を自分でできる
どれだけ簡単で読みやすいかを見てみましょう。
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非常に効率的で興味深いタンデムです
ただし、負荷の高いサーバーの場合は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;
...
')