我有一个日志文件,在一段时间后会不断更新(添加新行)。
我每 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没有内置功能seek
或tell
能力)。我本想发表评论,但我的声誉太低了。
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 -l
和tail
。
如果您使用的是 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 }