按时间戳(主键)和路径(按字典顺序)(辅助键)对来自多个日志文件的行进行线性排序

按时间戳(主键)和路径(按字典顺序)(辅助键)对来自多个日志文件的行进行线性排序

我正在尝试编写一个 bash 脚本,它接收目录的路径作为参数,并输出所有日志文件的所有行(来自给定的目录及其所有子目录),并按主键和辅助键排序。按主键排序需要在线性时间内(n 为总行数);辅助排序没有运行时限制。

编辑:输出行必须具有与原始文件完全相同的结构,因此对行/文件的任何更改都需要恢复为原始形式。我无法更改日志文件格式,因为我无法提前访问它们。输入文件的数量可能有几万个。

-主键时间戳格式如下:2018-07-23T14:66:55.456789123

-辅助键应该用于具有相同时间戳的行;辅助键是小路每行,从输入目录到它来自的文件。通过这个键进行排序按照字典顺序。

-所有日志文件都有“.log”扩展名

-所有单个日志文件都已按升序排序

-日志文件中的每一行日志都具有以下格式:以时间戳开头,后跟一个空格和一些文本,然后以 \0 结尾每行文本可以包含 \n

例子:

以下是 3 个示例文件:

$ cat input_dir/A/f3.log

2019-08-22T13:33:44.123456789 get

up 2

2020-01-01T11:22:33.123456789 love 2

$ cat input_dir/B/f2.log

2019-09-44T13:44:21.987654321 Nice line

$ cat input_dir/C/f1.log

2019-08-22T13:33:44.123456789 get

up

2020-01-01T11:22:33.123456789 love

这是我解决该任务最成功的尝试:

find $1 -name "*.log" -printf '%p\n' | sort | xargs sort -r -m -t "-" -k1,1 -k2,2 -k3,3

输出如下:

2019-09-44T13:44:21.987654321 Nice line

2019-08-22T13:33:44.123456789 get

up 2

2019-08-22T13:33:44.123456789 get

up

2020-01-01T11:22:33.123456789 love 2

2020-01-01T11:22:33.123456789 love

你可以看到除了第一行,它排序正确,并且看起来排序命令仅将 2019 至 2020 作为键进行比较......

我还尝试了大量可能的排序标志组合,包括指定不同的列(-k)、分隔符(-t),这些似乎对排序没有影响,可能是因为我使用了 -m 标志,但我无法避免它,因为它使运行时线性化,并且使排序路径稳定。此外,我尝试使用 -z 标志使多行保持在一起,但当我使用它时,它只按时间戳排序,而忽略了我试图传递给排序命令的排序路径。

我不知道是否可以通过简单地使用 sort 命令来解决此任务,但我不知道如何做。有人知道如何解决这个问题(在 bash 中)吗?谢谢

答案1

我很惊讶在任何地方都看不到-z参数(如果分隔符是,则需要\0),对我来说,分隔符是一个空格,您只需对第一个项目(即整个时间戳)进行排序。

您必须将文件名注入文件本身(时间戳之后),以便sort可以使用它来消除相同时间戳的歧义。如果已知文件数量,可以按如下方式完成:

sort -m -k2 -k1 <(sed 's/^/file1 /' file1) <(sed 's/^/file2 /' file2)

在哪里:

  • 每个sed子 shell 都会为文件添加路径前缀
  • 排序首先根据时间戳 (k2),然后根据文件名 (k1) 进行

对于可变数量的文件,您必须动态生成命令并使用eval或运行它bash -c

但:

  • 如果您的时间戳精确到纳秒,您几乎永远不会遇到两个相同的时间戳,因此这可能是多余的。
  • 如果这是您的应用程序,您还可以调整日志格式以注入名称并避免子外壳。
  • 在现代应用程序中,每个人都在使用某种形式的麋鹿堆。

相关内容