在UNIX中查找另一个文件中的一个文件的内容

时间:2013-06-21 11:24:05

标签: file grep

我有2个文件。第一个文件包含数据库中表的元组的行ID列表。 第二个文件包含查询的“where”子句中包含这些行ID的SQL查询。

例如:

档案1

1610657303
1610658464
1610659169
1610668135
1610668350
1610670407
1610671066

文件2

update TABLE_X set ATTRIBUTE_A=87 where ri=1610668350;
update TABLE_X set ATTRIBUTE_A=87 where ri=1610672154;
update TABLE_X set ATTRIBUTE_A=87 where ri=1610668135;
update TABLE_X set ATTRIBUTE_A=87 where ri=1610672153;

我必须阅读文件1并在文件2中搜索与文件1中的行ID匹配的所有SQL命令,并将这些SQL查询转储到第三个文件中。

文件1有1,00,000个条目,文件2包含10倍于文件1的条目,即1,00,0000。

我使用了grep -f File_1 File_2 > File_3。但这非常缓慢,每小时1000个条目。

有没有更快的方法呢?

8 个答案:

答案 0 :(得分:30)

您不需要regexp,因此grep -F -f file1 file2

答案 1 :(得分:17)

awk的一种方式:

awk -v FS="[ =]" 'NR==FNR{rows[$1]++;next}(substr($NF,1,length($NF)-1) in rows)' File1 File2

这应该很快。在我的机器上,花了不到2秒的时间创建了100万个条目的查找,并将其与300万行进行比较。

机器规格:

Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz (8 cores)
98 GB RAM

答案 2 :(得分:1)

我建议使用Perl,Ruby或Python等编程语言。

在Ruby中,只读一次文件(f1f2)的解决方案可能是:

idxes = File.readlines('f1').map(&:chomp)

File.foreach('f2') do | line |
  next unless line =~ /where ri=(\d+);$/
  puts line if idxes.include? $1
end

或使用Perl

open $file, '<', 'f1';
while (<$file>) { chomp; $idxs{$_} = 1; }
close($file);

open $file, '<', 'f2';
while (<$file>) {
    next unless $_ =~ /where ri=(\d+);$/;
    print $_ if $idxs{$1};
}
close $file;

答案 3 :(得分:1)

上面提到的awk / grep解决方案在我的机器上很慢或内存耗尽(file1 10 ^ 6行,file2 10 ^ 7行)。所以我想出了一个使用sqlite3的SQL解决方案。

将file2转换为CSV格式的文件,其中第一个字段是ri=

之后的值
cat file2.txt  | gawk -F= '{ print $3","$0 }' | sed 's/;,/,/' > file2_with_ids.txt

创建两个表:

sqlite> CREATE TABLE file1(rowId char(10));
sqlite> CREATE TABLE file2(rowId char(10), statement varchar(200));

从file1导入行ID:

sqlite> .import file1.txt file1

使用“准备好的”版本从文件2导入语句:

sqlite> .separator ,
sqlite> .import file2_with_ids.txt file2

使用表file2中匹配的rowId选择表file1中的所有语句并使其显示:

sqlite> SELECT statement FROM file2 WHERE file2.rowId IN (SELECT file1.rowId FROM file1);

通过在发出select语句之前将输出重定向到文件,可以轻松创建文件3:

sqlite> .output file3.txt

测试数据:

sqlite> select count(*) from file1;
1000000
sqlite> select count(*) from file2;
10000000
sqlite> select * from file1 limit 4;
1610666927
1610661782
1610659837
1610664855
sqlite> select * from file2 limit 4;
1610665680|update TABLE_X set ATTRIBUTE_A=87 where ri=1610665680;
1610661907|update TABLE_X set ATTRIBUTE_A=87 where ri=1610661907;
1610659801|update TABLE_X set ATTRIBUTE_A=87 where ri=1610659801;
1610670610|update TABLE_X set ATTRIBUTE_A=87 where ri=1610670610;

在没有创建任何索引的情况下,在AMD A8 1.8HGz 64位Ubuntu 12.04计算机上,select语句大约需要15秒。

答案 4 :(得分:0)

也许尝试AWK并使用文件1中的数字作为关键字,例如简单的脚本

第一个脚本将生成awk脚本:
awk -f script1.awk

 {
   print "\$0 ~ ",$0,"{ print \$0 }" > script2.awk;
 }

然后使用文件

调用script2.awk

答案 5 :(得分:0)

我可能遗漏了一些东西,但仅仅迭代file1中的ID和每个ID grep file2并将匹配存储在第三个文件中是不够的?即。

 for ID in `cat file1`; do grep $ID file2; done > file3

这不是非常有效(因为file2将被反复阅读),但它可能对你来说已经足够了。如果你想要更快的速度,我建议使用更强大的脚本语言,让你将file2读入地图,快速识别给定ID的行。

这是这个想法的Python版本:

queryByID = {}

for line in file('file2'):
  lastEquals = line.rfind('=')
  semicolon = line.find(';', lastEquals)
  id = line[lastEquals + 1:semicolon]
  queryByID[id] = line.rstrip()

for line in file('file1'):
  id = line.rstrip()
  if id in queryByID:
    print queryByID[id]

答案 6 :(得分:0)

以前的大多数答案都是正确的,但对我而言唯一有用的是该命令

grep -oi -f a.txt b.txt

enter image description here

答案 7 :(得分:-1)

##报告&lt;中包含的所有行。文件1&gt;缺少&lt;文件2&gt;

IFS=$(echo -en "\n\b") && for a in $(cat < file 1>); 
do ((\!$(grep -F -c -- "$a" < file 2>))) && echo $a; 
done && unset IFS

或做要求者想要的,取消否定并重定向

(IFS=$(echo -en "\n\b") && for a in $(cat < file 1>); 
do (($(grep -F -c -- "$a" < file 2>))) && echo $a; 
done && unset IFS) >> < file 3>