在linux命令行上按时间戳排序日志文件

时间:2011-09-08 11:05:38

标签: linux bash shell command-line logging

我有一个包含以下条目的日志文件:

...    
freeswitch.log:2011-09-08 12:21:07.282236 [ERR] ftdm_queue.c:136 Failed to enqueue obj 0x7f2cda3525c0 in queue 0x7f2ce8005990, no more room! windex == rindex == 58!
freeswitch.log:2011-08-08 13:21:07.514261 [ERR] ftdm_queue.c:136 Failed to enqueue obj 0x7f2cda354460 in queue 0x7f2ce8005990, no more room! windex == rindex == 58!
freeswitch.log:2011-06-04 16:21:08.998227 [ERR] ftdm_queue.c:136 Failed to enqueue obj 0x7f2cda356300 in queue 0x7f2ce8005990, no more room! windex == rindex == 58! 
freeswitch.log:2011-09-08 12:21:10.374238 [ERR] ftdm_queue.c:136 Failed to enqueue obj 0x7f2cda3581a0 in queue 0x7f2ce8005990, no more room! windex == rindex == 58!
...

如何通过每行下降的时间戳使用linux命令行工具对文件进行排序?

7 个答案:

答案 0 :(得分:17)

使用sort--stable--reverse--key选项:

sort --stable --reverse --key=1,2 freeswitch.log

(出于非教学目的,可以缩短为-srk1,2。)

sort命令(如您所料)以排序顺序输出命名文件(或STDIN)的每一行。这些选项的作用是什么:

  • --reverse选项告诉sort对具有更大值(更晚的日期)更高的行进行排序,而不是更低。根据其他答案,它假设这是你的意思,"降序" (即使通常会考虑这种排序"提升")。如果要按时间顺序对行进行排序,则省略此选项。
  • --key=1,2选项告诉sort仅使用前两个以空格分隔的"字段" (" freeswitch.log:" - 前缀日期和时间)作为排序的关键。指定要使用的 last 字段非常重要,即使您只按一个字段排序(例如,如果每行在ISO-8601标准字段中保存时间和日期,例如{{ 1}},您将使用freeswitch.log 2011-09-08T12:21:07.282236),默认情况下,键使用的字段将扩展到行尾
  • -k 2,2选项告诉--stable不执行"最后的订购"。如果没有此选项,则会根据整行对具有两个相等键(由sort选项指定)的行进行排序,这意味着文件名和/或内容将更改行的排序顺序。

指定--keys的两个范围以及--key选项非常重要。没有它们,同时发生的多行输出(换句话说,多行消息)将根据消息的内容(没有--stable中的第二个字段)和/或文件名(不含--key,如果文件名是单独的字段,如下所述)。

换句话说,这样的日志消息:

--stable

会得到"排序"成:

freeswitch.log:2011-09-08 12:21:10.374238 Warning: Syntax error on line 20:
freeswitch.log:2011-09-08 12:21:10.374238
freeswitch.log:2011-09-08 12:21:10.374238    My[brackets(call)
freeswitch.log:2011-09-08 12:21:10.374238               ^
freeswitch.log:2011-09-08 12:21:10.374238 Suggestion:
freeswitch.log:2011-09-08 12:21:10.374238   did you forget to
freeswitch.log:2011-09-08 12:21:10.374238   close your brackets?

这是"排序" (因为" c"来自" d"和" S"来自" W"),但它不是按顺序。指定freeswitch.log:2011-09-08 12:21:10.374238 freeswitch.log:2011-09-08 12:21:10.374238 ^ freeswitch.log:2011-09-08 12:21:10.374238 close your brackets? freeswitch.log:2011-09-08 12:21:10.374238 did you forget to freeswitch.log:2011-09-08 12:21:10.374238 My[brackets(call) freeswitch.log:2011-09-08 12:21:10.374238 Suggestion: freeswitch.log:2011-09-08 12:21:10.374238 Warning: Syntax error on line 20: (并保持--stable有界)将跳过额外的排序并保留订单,这就是您想要的。


此外,通过此组合的文件名和日期字段进行排序仅在输出中的每一行以相同的文件名开头时才有效。根据您发布的语法,如果您的输入有多个不同的文件名,您希望在排序时忽略这些文件名,则需要使用--key之类的程序将文件名转换为自己的空格分隔字段,然后管道转换后的文件到sed的行(之后你可以将字段分隔符转换回来):

sort

请注意,密钥使用的字段更改为sed 's/:/ /' freeswitch.log | sort -srk2,3 | sed 's/ /:/' ,跳过第一个(文件名)字段。

答案 1 :(得分:12)

使用sort的-k标志:

sort -k1 -r freeswitch.log

这将通过第一个键(即freeswitch.log:2011-09-08 12:21:07.282236)对文件进行反向排序。如果文件名始终相同(freeswitch.log),则应按日期排序。

答案 2 :(得分:1)

您可以使用

撤消排序
sort -r

答案 3 :(得分:1)

粗略但有效的技巧:使用日期的数字表示形式对每行进行前缀,以数字方式排序,然后删除额外的信息。

Oneliner:

while IFS=' ' read -r name_date trailing ; do date=$(cut -d: -f2 <<<"$name_date") ; printf '%s:%s\n' $(date -d "$date" +%s) "$name_date $trailing" ; done < freeswitch.log | sort -k1 -t: | cut -d: -f2-

Shell脚本:

#!/usr/bin/env bash

logfile="$1"

if [ -f "$logfile" ] ; then
    while IFS=' ' read -r name_date trailing ; do
            date=$(cut -d: -f2 <<<"$name_date")
        printf '%s:%s\n' $(date -d "$date" +%s) "$name_date $trailing"
    done < "$logfile" | sort -k1 -t: | cut -d: -f2-
fi

注意:需要GNU日期。

如果此时的输出与您想要的相反,则可以很容易地管道tac或修改脚本以将-r传递给sort

编辑:我错过了每行文字名称的部分。更新后的版本现在可以正常使用。

答案 4 :(得分:1)

您可以尝试使用sort

sort -k1,2 file

答案 5 :(得分:0)

日志文件似乎在升序,你可以

tac yourlogfile

会反向显示您的日志文件。

答案 6 :(得分:0)

我想日志文件会在最后添加新数据。如果是这样,您可以反过来阅读该文件。 尝试使用 tail -r cat 命令。