我有一个要求,我需要读取上次读取后更新的部分文件。我的意思是,如果我上次在 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