トラフィックが少ないnginx access.logがあるので、アクセスするたびに電子メールを受信したいと思います。頑張った
tail -f access.log | cat
これはうまくいきます。だから、テールパイピングを使っても大丈夫そうです。
以下では何も起こりません。
tail -f access.log | mail -s "Dateizugriff" <Destinationaddress>
どちらもありません
tail -f access.log | grep --line-buffered '.*' | mail -s "Dateizugriff" <Destinationaddress>
...でもない
stdbuf -oL -eL tail -f access.log | mail -s "Dateizugriff" <Destinationaddress>
もちろん動作します
echo "test" | mail -s "Dateizugriff" <Destinationaddress>
働く
それからxargsを試しました。
tail -f access.log | xargs -I % mail -s "Dateizugriff" <Destinationaddress>
1行に1つのメールを受け取りましたが、内容はありません。
tail -f access.log | xargs -I % | echo "%" | mail -s "Dateizugriff" <Destinationaddress>
動作しません。何もしません。以下も機能しません。
tail -f access.log | xargs | mail -s "Dateizugriff" <Destinationaddress>
では、うまくいく秘訣は何ですか?
ベストアンサー1
問題は、tail -fが決して終了しないことです。ただ入力を永遠に待つだけです。したがって、パイプは開いたままであり、メッセージはEOFを受信せず、メッセージが「完了」するのを待ちます。これは決して不可能です。
パイプに別のプロセスを追加することは、プロセスの少なくとも1つが終了してパイプを破壊しない限り役に立ちません。
ログに追加された各行を別々のメッセージとして表示するには、次のようにします。
tail -f access.log | head -n 1 | mail -s "Dateizugriff" <user@domain>
Headは1行を読んだ後に終了し、tailはSIGPIPEを受信してから終了し、mailはEOFを受信した後に電子メールを送信し続けます。
ログエントリが複数行になる可能性がありますが、常に最後の行を識別できる場合は、sedおよびaq条件を使用してパイプを破棄できます。
最初の欠点は、メールプロセスが次の行が到着するのを待って永久に中断されることです。
2番目の欠点は、毎回プロセスが完了したことを認識し、プロセス全体を再起動する必要があることです。
個人的には、休眠(約60秒)を含むループ内で追加された行を見つけようとする繰り返しのシェルループを作成します。ファイルサイズが大きくなると、-fなしでtailを実行できるため停止しません。
繰り返す前に、nLineを現在の行番号に初期化します。リダイレクトは、wcがファイル名と数を報告するのを防ぐため、重要です。
nLine="$( wc -l < access.log )"
while : ; do
NEW=$( tail -n +$(( 1 + nLine )) access.log )
[[ "${#NEW}" -gt 0 ]] && {
echo "${NEW}" | mail ....
nLine=$(( nLine + $( wc -l <<<${NEW} ) ))
}
sleep 60
done