我正在尝试编写一个 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
。
但:
- 如果您的时间戳精确到纳秒,您几乎永远不会遇到两个相同的时间戳,因此这可能是多余的。
- 如果这是您的应用程序,您还可以调整日志格式以注入名称并避免子外壳。
- 在现代应用程序中,每个人都在使用某种形式的麋鹿堆。