Evg*_*sky 7 linux unix merge command-line
如何合并日志文件,即按时间排序但也有多行的文件,其中只有第一行有时间,其余的没有。
日志1
01:02:03.6497,2224,0022 foo
foo1
2foo
foo3
01:04:03.6497,2224,0022 bar
1bar
bar2
3bar
Run Code Online (Sandbox Code Playgroud)
日志2
01:03:03.6497,2224,0022 FOO
FOO1
2FOO
FOO3
Run Code Online (Sandbox Code Playgroud)
预期结果
01:02:03.6497,2224,0022 foo
foo1
2foo
foo3
01:03:03.6497,2224,0022 FOO
FOO1
2FOO
FOO3
01:04:03.6497,2224,0022 bar
1bar
bar2
3bar
Run Code Online (Sandbox Code Playgroud)
如果不是以数字开头的非时间戳行,那么简单sort -nm log1 log2
就行了。
在 unix/linux cmd 行上是否有一种简单的方法来完成工作?
编辑由于这些日志文件通常以 GB 为单位,因此合并应该在不重新排序(已经排序的)日志文件的情况下完成,也不要将文件完全加载到内存中。
ter*_*don 10
棘手。虽然可以使用date
和 bash 数组,但这确实是一种可以从真正的编程语言中受益的东西。以 Perl 为例:
$ perl -ne '$d=$1 if /(.+?),/; $k{$d}.=$_; END{print $k{$_} for sort keys(%k);}' log*
01:02:03.6497,2224,0022 foo
foo1
2foo
foo3
01:03:03.6497,2224,0022 FOO
FOO1
2FOO
FOO3
01:04:03.6497,2224,0022 bar
1bar
bar2
3bar
Run Code Online (Sandbox Code Playgroud)
这是未压缩到注释脚本中的相同内容:
$ perl -ne '$d=$1 if /(.+?),/; $k{$d}.=$_; END{print $k{$_} for sort keys(%k);}' log*
01:02:03.6497,2224,0022 foo
foo1
2foo
foo3
01:03:03.6497,2224,0022 FOO
FOO1
2FOO
FOO3
01:04:03.6497,2224,0022 bar
1bar
bar2
3bar
Run Code Online (Sandbox Code Playgroud)
请注意,这假定所有日期行和仅日期行包含逗号。如果不是这种情况,您可以改用它:
perl -ne '$d=$1 if /^(\d+:\d+:\d+\.\d+),/; $k{$d}.=$_; END{print $k{$_} for sort keys(%k);}' log*
Run Code Online (Sandbox Code Playgroud)
上述方法需要将文件的全部内容保存在内存中。如果这是一个问题,这里有一个没有问题:
$ perl -pe 's/\n/\0/; s/^/\n/ if /^\d+:\d+:\d+\.\d+/' log* |
sort -n | perl -lne 's/\0/\n/g; printf'
01:02:03.6497,2224,0022 foo
foo1
2foo
foo3
01:03:03.6497,2224,0022 FOO
FOO1
2FOO
FOO3
01:04:03.6497,2224,0022 bar
1bar
bar2
3bar
Run Code Online (Sandbox Code Playgroud)
这只是通过替换换行符将连续时间戳之间的所有行放在一行中\0
(如果这可以在您的日志文件中,请使用您知道永远不会出现的任何字符序列)。这传递给sort
然后tr
让线路回来。
正如 OP 非常正确地指出的那样,需要采用上述所有解决方案,并且不考虑可以合并文件。这是一个可以,但与其他的不同,它只能处理两个文件:
$ sort -m <(perl -pe 's/\n/\0/; s/^/\n/ if /^\d+:\d+:\d+\.\d+/' log1) \
<(perl -pe 's/\n/\0/; s/^/\n/ if /^\d+:\d+:\d+\.\d+/' log2) |
perl -lne 's/[\0\r]/\n/g; printf'
Run Code Online (Sandbox Code Playgroud)
如果将 perl 命令保存为别名,则可以获得:
$ alias a="perl -pe 's/\n/\0/; s/^/\n/ if /^\d+:\d+:\d+\.\d+/'"
$ sort -m <(a log1) <(a log2) | perl -lne 's/[\0\r]/\n/g; printf'
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5453 次 |
最近记录: |