我需要比较两个文件并打印匹配的行。如果 file1 用户名位于 file2 (字段 1)中,我想将其打印到新的匹配文件中。
文件1.txt:
Hey123
Johnson
Hanny123
Fanny
(文件 1 为 240MB - 20.000.000 行)
文件2.txt:
Gromy123:hannibal
Hey123:groll
Hanny123:tronda9
Kroppsk:football23
(文件 2 为 1.4GB - 69.000.000 行)
预期的匹配行输出:
Hanny123:tronda9
Hey123:groll
我已经尝试了4个小时没有成功。这两个文件都已排序,我尝试过 join + 无数的 grep / awk 命令。我的大问题是内存耗尽。我希望得到一些帮助,我可以如何处理这个如此大的文件。
答案1
如果文件已排序(您发布的示例是),那么就很简单
join -t : File1.txt File2.txt
join
将连接字段相等的两个文件中的行配对。默认情况下,连接字段是第一个字段,除了连接字段不重复外,字段按顺序输出,并且跳过不可配对的行,这正是您想要的。
请注意,如果文件有Windows 行结束符,它们在 Unix 系统下出现在每行末尾有一个额外的回车符。 CR 大部分在视觉上是不可见的,但就join
其他文本工具而言,它是一个与其他字符一样的字符,这意味着所有字段都File1.txt
以 CR 结尾,而 中的字段则File2.txt
不然,因此它们不匹配。您需要删除 CR,至少在File1.txt
.
<File1.txt tr -d '\r' | join -t : - File2.txt
您确实需要对文件进行排序。如果不是,那么 ksh/bash/zsh,您可以使用进程替换。 (如果需要的话添加tr -d '\r' |
。)
join -t : <(sort File1.txt) <(sort File2.txt)
在普通的 sh 中,如果您的 Unix 变体有/dev/fd
(大多数有),您可以使用它通过两个文件描述符通过管道传输两个程序的输出。
sort File2.txt | { sort File1.txt | join -t : /dev/fd/0 /dev/fd/3; } 3<&1
如果您需要保留原始顺序File1.txt
并且未按连接字段排序,请添加行号以记住原始顺序,按连接字段排序,连接,按行号排序并删除行号。 (如果您想保留其他文件的顺序,您可以执行类似的操作。)
<File1.txt nl -s : |
sort -t : -k 2 |
join -t : -1 2 - <(sort File2.txt) |
sort -t : -k 2,2n |
cut -d : -f 1,3
答案2
如果您有 2GB 的可用 RAM,请尝试
awk -F: 'NR==FNR { n[$0]++ ; next}; $1 in n ' file1 file2 > file3
答案3
一个可能的解决方案(这当然适用于您的小例子):
#!/bin/bash
# because File2.txt is bigger, it gets the main loop.
# read each line of File2.txt
while read string; do
# read each line of File1.txt
while read string2; do
# check match, and write if needed.
if [[ $string == *"$string2"* ]]; then
echo $string >> match_output.txt
echo "wrote "$string" to match_output.txt..."
fi
done < File1.txt
done < File2.txt