根据@Masi 的要求,我尝试使用 sed 制定解决方案。
我的第一次尝试使用了两次传球;第一个转换file1
成一个 sed 脚本,在第二个 pass 中用于 filter file2
。
sed 's/\([^ \t]*\).*/\/^\1\t\/p;t/' file1 > sed1
sed -nf sed1 file2 > out2
对于大输入文件,这很慢;对于 中的每一行file2
,sed 必须处理的模式数量等于 中的行数file1
。我没有做过任何分析,但如果时间复杂度是二次的,我不会感到惊讶。
我的第二次尝试合并和排序这两个文件,然后扫描所有行以搜索对。这在线性时间内运行,因此要快得多。请注意,此解决方案会破坏文件的原始顺序;字母排序不适用于此日期表示法。提供具有不同日期格式 (ymd) 的文件将是解决此问题的最简单方法。
sed 's/^[^ \t]\+/&@1/' file1 > marked1
sed 's/^[^ \t]\+/&@2/' file2 > marked2
sort marked1 marked2 > sorted
sed '$d;N;/^\([^ \t]\+\)@1.*\n\1@2/{s/\(.*\)\n\(.*\)/\2\n\1/;P};D' sorted > filtered
sed 's/^\([^ \t]\+\)@2/\1/' filtered > out2
解释:
- 在第一个命令中,
s/^[^ \t]\+/&@1/
附加@1
到每个日期。这使得合并文件成为可能,在排序时将相同的日期保持在一起,并且仍然能够区分来自不同文件的行。
- 第二个命令对
file2
;执行相同的操作 显然带有自己的标记@2
。
- 该
sort
命令合并两个文件,将相等的日期组合在一起。
- 第三个 sed 命令返回
file2
日期也出现在file1
.
- 第四个 sed 命令
@2
从输出中删除标记。
第三条 sed 命令详解:
$d
禁止不恰当地打印最后一行
N
读取另一行输入并将其附加到模式空间中已经存在的行
/^\([^ \t]\+\)@1.*\n\1@2/
匹配来自不同文件但日期相同的两行
{
启动命令组
s/\(.*\)\n\(.*\)/\2\n\1/
交换模式空间中的两行
P
打印模式空间中的第一行
}
结束命令组
D
从模式空间中删除第一行
坏消息是,即使是第二种方法也比@John1024 提出的 awk 方法慢。Sed 从来没有被设计成一个合并工具。awk 也不是,但 awk 的优势在于能够将整个文件存储在字典中,这使得 @John1024 的解决方案非常快。字典的缺点是内存消耗。在巨大的输入文件上,我的解决方案应该有优势。