增量读取文件

增量读取文件

我有一个要求,我需要读取上次读取后更新的部分文件。我的意思是,如果我上次在 2016-07-26T01:30 读取该文件,然后我想在 2016-07-26T02:30 再次运行,其中文件中更新了 100 条记录,那么我只需要读取这 100 条记录整个文件的。

文件格式为:

[2016-07-26T16:26:31.953-04:00] [AnalyticProviderServices0] [ERROR] [] [oracle.EPMOHPS] [tid: 17] [userId: <anonymous>] [ecid: 0000LGXnLUEComOpyg4EyW1N4iIi000002,1:28342] [APP: APS#11.1.2.0] Unable to resolve 'jdbc.EPMSystemRegistry'. Resolved 'jdbc'[[
[2016-07-26T16:26:31.954-04:00] [AnalyticProviderServices0] [WARNING] [] [oracle.EPMOHPS] [tid: 17] [userId: <anonymous>] [ecid: 0000LGXnLUEComOpyg4EyW1N4iIi000002,1:28342] [APP: APS#11.1.2.0] Failure while getting the active Essbase node for cluster [SWESSPROD1]. Runtime Provider Services Error: [Unable to resolve 'jdbc.EPMSystemRegistry'. Resolved 'jdbc']

答案1

有一个名为 Re-Tail 或“retail”的命令行实用程序(从 2003 年开始),每次在日志文件上运行该程序时,它都会增量读取日志文件。

例如,这对于每小时运行的 cron 作业来说非常有用。

Re-Tail 将状态保存在“偏移文件”中;对于运行它的每个文件,它将存储最后的行号以及该行号上的文本。

下次运行该程序时,它将尝试查找存储的行号并比较内容。如果存在匹配,它将输出文件的其余部分,从下一行开始。如果磁盘上文件中的行较少,或者行内容不匹配,则假定该文件已被清除或旋转,在这种情况下,它将从第一行开始。

最后,零售将更新保存的行号和内容。

该软件位于:http://xjack.org/retail/

当我以root身份运行retail时,我喜欢将保存的状态放在/var/lib/retail中。例如,在一台计算机上,我使用包含以下命令行的脚本每小时运行零售来生成有关 SSH 登录的报告:

/usr/local/bin/retail -p /var/lib/retail/ /var/log/secure >"$tempfile"

祝你好运!

答案2

您可以使文件保持打开状态:

exec 3< file
cat <&3

sleep 3600

echo After one hour, these records were added:
cat <&3

cat这意味着它必须是调用这些一小时的相同过程。


如果文件系统上启用了访问时间,并且您的脚本是唯一读取该文件的内容,则您还可以读取时间戳晚于上次访问时间的行。在 GNU 系统上:

awk -v last_access="$(find file -prune -printf %AFT%AT)" '
   $0 > last_access' < file

假设-04:00日志文件中的 对应于当前时区偏移量。


另一种方法是在某处记录当前文件位置,例如file.pos

{
   if [ -e file.pos ]; then
     pos=$(cat file.pos)
   else
     pos=0
   fi
   tail -c +"$((pos+1))"
   perl -le 'print tell STDIN' > file.pos
} < file

或者与ksh93

{
   if [ -e file.pos ]; then
     pos=$(<file.pos)
   else
     pos=0
   fi
   cat <#((pos))
   exec <#((pos=CUR))
   echo "$pos" > file.pos
} < file

或者与zsh

zmodload zsh/system    
{
   if [ -e file.pos ]; then
     pos=$(<file.pos)
   else
     pos=0
   fi
   sysseek $pos
   cat
   echo "$((systell(0)))" > file.pos
} < file

答案3

#!/bin/bash

logfile="$1"

test -f "$logfile" || exit 1

lastline="$( basename "$logfile" )-last"

if [ -f "$lastline" ]; then
    place=$( <"$lastline" )
else
    place=1
fi

tmpfile="$( mktemp )"
trap 'rm -f "$tmpfile"' EXIT

sed -n -e "$place,\$p" -e '$=' "$logfile" |
tee "$tmpfile" |
tail -n 1 >"$lastline"

sed '$d' "$tmpfile"

这个小脚本将在命令行上获取一个日志文件,并显示自您上次使用该脚本以来添加的所有行。 它不理解当前形式的日志文件轮换...-last,因此如果日志发生轮转,您需要手动删除它在当前目录中创建的文件。

它能做什么:

首次运行时,它用于sed将给定日志文件的所有行输出到临时文件,后跟最后一行的行号。该数字也存储到当前目录中的一个文件中,该文件与日志文件同名,后缀为-last.然后,临时文件(不包含包含行号的最后一行)将输出到终端(less如果需要,可以通过管道将脚本的输出发送到终端)。当脚本退出时,临时文件将被删除。

再次运行时,将从当前目录中的文件中读取行号...-last,并以与以前类似的方式从该行号开始处理日志文件的内容到末尾。

如果在此脚本运行之间没有向日志文件输出任何内容。将显示日志文件的最后一行。

运行它:

$ bash script.sh /var/log/system.log
[lots of output]

$ ls system*
system.log-last

$ cat system.log-last
14758

$ bash script.sh /var/log/system.log
[a few lines of output,
 with the first line being the same as the last of the previous run]

$ cat system.log-last
14768

相关内容