從上次離開的位置繼續讀取日誌檔案

從上次離開的位置繼續讀取日誌檔案

我有一個日誌文件,在一段時間後會不斷更新(添加新行)。

我每 10 分鐘僅從文件中獲取錯誤訊息。

最初,第一次我將所有行提取到一個新文件中,並使用匹配模式“ERROR FOUND”awk

但 10 分鐘後,日誌檔案中新增了更多新行,因此我想讀取我離開的位置的日誌檔案。我不想再從頭開始。

有人可以建議我最好的程式碼或腳本嗎?

答案1

如果您在文件描述符上開啟文件,例如:

exec 3< /path/to/log/file

然後你可以處理它:

awk '...' <&3

之後 fd 3 將指向awk它左邊的位置。

10 分鐘後,從同一個 shell 呼叫中,您可以執行該命令

awk '...' <&3

再次命令處理新資料。

如果您想保存您所在的位置,以便可以從不同的 shell 呼叫中恢復讀取,ksh93可以使用 ,您可以執行以下操作:

#! /usr/bin/env ksh93
file=/path/to/some-file
offset_file=$file.offset

exec 3< "$file"
[ -f "$offset_file" ] && exec 3<#(($(<"$offset_file")))

awk '...' <&3

echo "$(3<#((CUR)))" > "$offset_file"

或使用 zsh:

#! /usr/bin/env zsh

zmodload zsh/system
file=/path/to/some-file
offset_file=$file.offset

exec 3< $file
[ -f "$offset_file" ] && sysseek -u 3 "$(<$offset_file)"

awk '...' <&3

echo $((systell(3))) > $offset_file

答案2

我喜歡 Stéphane 的答案,因為它不會一次又一次地讀取整個文件,所以我在這裡添加巴什(在Linux上)相當於他的解決方案(bash沒有內建功能seektell能力)。我本來想發表評論,但我的聲譽太低了。

LASTPOS=/tmp/saved_pos

exec 3< "$1"
test -f "$LASTPOS" && STARTPOS=$(($(<$LASTPOS)+1))
tail -c "+${STARTPOS:-1}" <&3 | grep "ERROR FOUND"
grep '^pos:' /proc/self/fdinfo/3 | cut -f2 > "$LASTPOS"

我還awk用 a 替換了該命令,grep因為它通常更快。awk如果需要進一步處理,可以將輸出透過管道傳輸到命令。

答案3

我會嘗試使用wc -ltail
如果您使用的是 bash,這應該可以工作:

#!/bin/bash
LASTLNFILE=/tmp/lastline     # replace with a suitable path
test -f $LASTLNFILE && LASTLN=$(<$LASTLNFILE)
CURLN=$(wc -l $1 | cut -d' ' -f1)

if ((CURLN-LASTLN > 0)); then
  tail -n $((CURLN-LASTLN)) $1
fi
echo $CURLN > $LASTLNFILE

PS 在 awk 程式之前將其用作過濾器,例如(假設您將其命名為「newlines.sh」):

./newlines.sh <log_file> | awk -f <your_awk_program>`

我將上面的腳本作為範例來說明如何不做。寫完之後,我意識到只要在腳本運行時更新日誌文件,它就很容易受到競爭條件的影響。

最好使用純 AWK 方法:

#!/bin/awk

BEGIN { 
  lastlinefile = "/tmp/lastlinefile"
  getline lastline < lastlinefile
}

NR > lastline && /ERROR FOUND/ {
  # do your stuff...
  print
}

END { print NR > lastlinefile }

相關內容