在bash中的特定时间戳期间计算文件中的行数

在bash中的特定时间戳期间计算文件中的行数,bash,awk,timestamp,Bash,Awk,Timestamp,我正在安排一个cron,它每分钟运行一次,并给出每分钟REJECT的字数。我的文件是连续记录的,为了避免重复读取,我在使用tail-n+lastTimeWC运行脚本时存储了上次读取的行。但我如何计算每分钟被拒绝的次数呢。样本输入: 20170327-09:15:01.283619074 ResponseType:REJECT 20170327-09:15:01.287619074 ResponseType:REJECT 20170327-09:15:01.289619074 ResponseTy

我正在安排一个cron,它每分钟运行一次,并给出每分钟
REJECT
的字数。我的文件是连续记录的,为了避免重复读取,我在使用tail-n+lastTimeWC运行脚本时存储了上次读取的行。但我如何计算每分钟被拒绝的次数呢。样本输入:

20170327-09:15:01.283619074 ResponseType:REJECT
20170327-09:15:01.287619074 ResponseType:REJECT
20170327-09:15:01.289619074 ResponseType:REJECT
20170327-09:15:01.290619074 ResponseType:REJECT
20170327-09:15:01.291619074 ResponseType:REJECT
20170327-09:15:01.295619074 ResponseType:REJECT
20170327-09:15:01.297619074 ResponseType:REJECT
20170327-09:16:02.283619074 ResponseType:REJECT
20170327-09:16:03.283619074 ResponseType:REJECT
20170327-09:17:02.283619074 ResponseType:REJECT
20170327-09:17:07.283619074 ResponseType:REJECT
预期产出:

9:15 REJECT 7
9:16 REJECT 2
9:17 REJECT 2
更新1:(使用埃德·莫顿的答案)


这个脚本在60秒后不断地给我输出。但是它应该只给日志文件添加新的时间戳。
($!)
假设添加了9:18,那么它应该开始将其包含到答案中(不再是9:15到9:18)

您可以在
Awk
中这样做,方法是将分钟值散列为索引,并假设状态每分钟不变,如下所示

awk -F'[-:]' '{unique[$2":"$3]++; uniqueValue[$2":"$3]=$NF; next}END{for (i in unique) print i,uniqueValue[i],unique[i]}' file
09:15 REJECT 7
09:16 REJECT 2
09:17 REJECT 2

包括拒绝过滤器、日期和流中版本(内存中没有数组,只有最后一个计数器和日期引用)

awk -F '-|:..[.]|pe:' '$NF=="REJECT"{if(L==$1"-"$2)C++;else{print L" REJECT " C;C=1;L=$1"-"$2}}END{print L" REJECT " C}' YourLog
包括注释中询问的“不退回相同信息”(只需在代码中查看重新读取的“最后知道的时间”)


不要打印最后一次计数,因为该时间戳可能不完整,只需打印之前的计数:

$ awk -F '[:-]' '{curr=$2":"$3} (prev!="") && (curr!=prev){print prev, cnt, $NF; cnt=0} {cnt++; prev=curr}' file
09:15 REJECT 7
09:16 REJECT 2
如果您真的想打印最后一个,那么只需在结尾部分添加一个打印:

$ awk -F '[:-]' '{curr=$2":"$3} (prev!="") && (curr!=prev){print prev, $NF, cnt; cnt=0} {cnt++; prev=curr} END{print prev, $NF, cnt}' file
09:15 REJECT 7
09:16 REJECT 2
09:17 REJECT 2
但我想你必须放弃可能的部分结果,那有什么意义呢

请注意,您不必将所有结果存储在一个数组中,然后在结束部分打印它们,只要在每次时间戳更改时打印它们即可。除了不必要地使用内存外,将所有结果存储在一个数组中,然后在结束部分使用
in
循环打印它们的解决方案将打印输出以随机(实际上是散列)顺序,而不是时间戳在输入中出现的顺序(除非有时运气不好)

而不是存储输入文件的行数(当跨脚本调用分割时间戳结果时,可能会导致错误结果,并且无法使用
logrotate
或类似工具在日志文件变长/变旧时截断日志文件),存储分析的最后一个时间戳,然后在当前迭代中开始,例如,使用cron执行等效操作:

while :
do
    results=( $(awk -F '[:-]' -v last="$lastTimeStamp" '{curr=$2":"$3} curr<last{next} (prev!="") && (curr!=prev){print prev, $NF, cnt; cnt=0} {cnt++; prev=curr}' file) )
    numResults="${#results[@]}"
    if (( numResults > 0 ))
    then
        printf '%s\n' "${results[@]}"
        (( lastIndex = numResults - 1 ))
        lastResult="${results[$lastIndex]}"
        lastTimeStamp="${lastResult%% *}"
    fi
    sleep 60
done
在打印结果之前,将其剥离以保存最后一个值。最后一个值就是您将在下一次迭代中执行的
tail-n+|awk'…'


顺便说一句,您在示例输入中没有向我们显示这一点,但是如果您的日志文件包含不包含REJECT的行,并且希望忽略这些行,只需添加
$NF!=“REJECT”{next}
在awk脚本的开头。

是的,我放了一个分钟的cron,但这不可能是精确的,所以我从递增的日志中删去uniq hr:min,并想从该时间和grep-c中减去1分钟。但是仍然很复杂,我想找到一些解决这个问题的方法,而不是代码谢谢,这看起来是一个不错的方法。`假设状态不是每分钟更改一次。这意味着什么?基本上这个文件是连续写入的。因此,在9:15,当我的cron脚本告诉我9:15的10行时间时,我无法确定9:15的日志记录是否结束。因此我认为我们应该提前一分钟检查(以确保所有9:14都被考虑在内)然后在9:16我们检查所有的9:15等等。(可能有更好的方法,但这就是我现在的想法)@pythonRcpp:我只是说状态
拒绝
不会在一分钟内改变,例如在
9:15
的30秒内是
拒绝
,在接下来的30秒内是另一种状态。不,一旦有什么东西被记录下来,它会永久保留。我希望你能理解我的问题(通过运行一分钟或两分钟后的时间戳,确保考虑到所有每分钟的值)@pythonRcpp:你真的可以在日志文件中运行这个并报告回来吗?看看它是否工作。如果它不能解决你的问题,我将删除它。@Inian-只是为了添加一个较短版本的代码-
awk-F'[-:]'{a[$2:“$3”“$NF]+}结束{for(i in a)print i,a[i]}f
Mortan,谢谢你的回答。
对cron做类似的处理
这是否意味着使用while代码放置cron脚本?我希望我的问题很清楚(该文件的长度不断增加),我需要一个分钟拒绝计数日志文件(即使它延迟2-3分钟),此日志文件每分钟追加一次第8行:结果:当文件不随新时间更新时,数组下标不正确我理解您的意图。不,我不是说将其放在cron作业中-有两种方法可以每分钟调用一个脚本,一种是来自cron作业,另一种是带有sleep 60的循环,如我所示。我只是说执行相同的操作在cron作业中使用ent。您确实说过
我在寻找解决此问题的方法,而不是代码
。只需在访问数组元素之前添加一个数组非空(
((numResults!=0))
)的测试。我仍在学习awk,不清楚此代码是如何工作的。每60秒打印一次(之前打印的内容,也不需要持续检查状态是否更新。打印完成后,不应重新评估)。我想你正在考虑这样的情况,在9:20时,我得到了一个9:15
拒绝
,应该更新我的拒绝计数。但这不是必需的,因为文件是连续记录的。很抱歉,我不确定我是否理解你的评论。脚本每60秒打印一次过去60秒记录的内容。wrt
在9:20时,我得到了一个9:15 rej所有脚本都不打印文件中最后一个时间戳的统计信息,因为生成日志文件的任何内容可能在该脚本运行时记录在该时间戳的中间,因此脚本不知道最后的记录是否完成。它不试图重新分析先前报告的时间戳。记录。只需尝试运行它。添加一些
打印
s以帮助跟踪它正在执行的操作(如果您愿意)。它是否确保不会重新读取
$ awk -F '[:-]' '{curr=$2":"$3} (prev!="") && (curr!=prev){print prev, $NF, cnt; cnt=0} {cnt++; prev=curr} END{print prev, $NF, cnt}' file
09:15 REJECT 7
09:16 REJECT 2
09:17 REJECT 2
while :
do
    results=( $(awk -F '[:-]' -v last="$lastTimeStamp" '{curr=$2":"$3} curr<last{next} (prev!="") && (curr!=prev){print prev, $NF, cnt; cnt=0} {cnt++; prev=curr}' file) )
    numResults="${#results[@]}"
    if (( numResults > 0 ))
    then
        printf '%s\n' "${results[@]}"
        (( lastIndex = numResults - 1 ))
        lastResult="${results[$lastIndex]}"
        lastTimeStamp="${lastResult%% *}"
    fi
    sleep 60
done
$ awk -F '[:-]' '{curr=$2":"$3} (prev!="") && (curr!=prev){print NR, prev, $NF, cnt; cnt=0} {cnt++; prev=curr}' file
8 09:15 REJECT 7
10 09:16 REJECT 2