プログラムが実行されるたびに削除され、再生成されるログファイルから情報を抽出する必要があります。ファイルが存在することを(再度)検出した後、tail
正規表現で使用したいと思います。
正規表現は複数回一致しますが、結果は常に同じです。一度だけ印刷してからファイルが再生成されたら、ウォッチ式を返したいと思います。
ファイル生成を検出する方法を見てみました。パスするのも一つの方法inotifywait
ただし、これを行うには別々のパッケージをインストールする必要があります。
stderr
おそらくより簡単なアプローチは、末尾のファイルを削除して作成するときに後続の印刷を利用することです。
tail: '/path/to/debug.log' has become inaccessible: No such file or directory
tail: '/path/to/debug.log' has appeared; following new file
だから申請しました。このソリューションランニング:
debug_file="/path/to/debug.log"
while true; do
# Monitor the log file until the 'new file' message appears
( tail -F $debug_file 2>&1 & ) | grep -q "has appeared; following new file"
# After the new file message appears, switch to monitoring for the regexp
tail -F "$debug_file" | while read -r line; do
id=$(echo "$line" | sed -n 's/.* etc \([0-9]\+\),.*/\1/p')
if [ -n "$id" ]; then
echo "ID: $id"
break # Exit the inner loop after the first match
fi
done
done
しかし、私は2つの異なるプロセスを開始するこのソリューションが好きではありませんtail
。 1つのプロセスのみを使用して同じ結果を得る方法はありますかtail
?
その後、「モード」を切り替えて最初にファイル生成を見つけ、正規表現を見つけて「スタンバイ」モードに戻り、ログファイルが削除され再生成されるのを待ちます。
inotifywaitはよりエレガントなソリューションですか?理想的には、Windows CMDに簡単に移植できるソリューションが必要です。
答え1
外部ループは必要ないようです。テール出力を読み取りにパイプすると、2つの状態にある状態マシンで動作できます。一般的なテール状態と新しいファイル状態では、次の一致が「ID:」行を印刷するのを待ちます。
しかし、読んでいるときにstderrをstdoutにリダイレクトすることをお勧めします。あなたの例にいくつかの疑似コードを追加しました。
debug_file="/path/to/debug.log"
# After the new file message appears, switch to monitoring for the regexp
# state="new_file"
tail -F "$debug_file" 2>&1 | while read -r line; do
# if state = "new_file"
id=$(echo "$line" | sed -n 's/.* etc \([0-9]\+\),.*/\1/p')
if [ -n "$id" ]; then
echo "ID: $id"
# state = "id_printed"
fi
# else
# if line contains "has appeared; following new file"
# state = new_file
# echo "$line"
# fi
done
編集する。ファイルの正規表現に一致する複数の項目があり、最初の項目のみを一致させたい場合は、上記の回避策を使用する必要があります。それ以外の場合は、やや複雑な単一のライナーを作成する可能性がありますtail -F | grep | sed
(sedの代わりにawkを使用することもできます)。必要に応じて、-oオプションを使用してtailとgrepのみを使用して操作を完了することもできます。
たとえばtail -F /path/to/debug.log | grep -E '.* etc ([0-9]+),.*'
、次のことを試してからそこからどのように変換するかを確認します。
答え2
使用TxR不明な言葉:
(open-tail "/path/to/debug.log") ;; returns a stream that follows rotating log
たとえば、次のようにそのストリームから入力を読み込みます。
(with-stream (s (open-tail "/path/to/debug.log"))
(whilet ((ln (get-line s)))
(if-match `@nil etc @id,@nil` ln
(put-line `ID: @id`))))
答え3
ゲーム内でファイルを継続的に追跡する必要がある唯一の行と出力は次のとおりです。
tail -F "$debug_file" 2>/dev/null | awk '!seen[$0]++'
sedコマンドのregexpによって生成された行の一部のみを考慮したい場合は、sed -n 's/.* etc \([0-9]\+\),.*/\1/p'
GNU awkの3rg argを使用してこれを実行できます(テストされていません)。match()
tail -F "$debug_file" 2>/dev/null |
awk 'match($0,/.* etc ([0-9]+),/,a) && !seen[a[1]]++ { print "ID: " a[1] }'
または awk を使用してください。
tail -F "$debug_file" 2>/dev/null |
awk '/.* etc [0-9]+,/ && sub(/.* etc /,"") && sub(/,.*/,"") && !seen[$0]++ { print "ID: " $0 }'
前の入力反復で表示された「ID」を削除するには、次のようにします。
tail -F "$debug_file" 2>&1 |
awk '
/^tail: \047.*\047 has appeared; following new file$/ { delete seen }
... code from above ...
'
追跡するファイル自体には、^tail:.*
この正規表現に一致する行を含めることはできません。
これは次のような可能性があります。
awk '/.* etc [0-9]+,/ && sub(/.* etc /,"") && sub(/,.*/,"") && !seen[$0]++ { print "ID: " $0 }'
これは実際には次のようにより簡潔な形式で書くことができます。
awk '$(X-1) == "etc" && !seen[$X]++ { print "ID: " $X+0 }'
ID番号を含むスペースで区切られたフィールド番号はどこにありますかX
?しかし、ログファイルの例を見ずにこれがうまくいくのか、そうであればX
どのような値があるのか、状況が正確にどんなものなのかはわかりません。