削除および再生成されるログファイルを継続的に追跡する方法は?

削除および再生成されるログファイルを継続的に追跡する方法は?

プログラムが実行されるたびに削除され、再生成されるログファイルから情報を抽出する必要があります。ファイルが存在することを(再度)検出した後、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どのような値があるのか​​、状況が正確にどんなものなのかはわかりません。

関連情報