如何在linux中减去这两个文件

时间:2013-08-15 20:36:24

标签: linux shell sed awk grep

我有两个文件如下:

文件1

"Connect"    CONNECT_ID="12"
"Connect"    CONNECT_ID="11"
"Connect"    CONNECT_ID="122"
"Connect"    CONNECT_ID="109"

file2的

"Quit"    CONNECT_ID="12"
"Quit"    CONNECT_ID="11"

文件内容不完全相同,但与上述类似,记录数最少为100,000。

现在我想将结果如下所示显示在 file1 中(表示最终结果应该在file1中)

"Connect"    CONNECT_ID="122"
"Connect"    CONNECT_ID="109"

我使用了类似下面的while循环:

awk {'print $2'} file2 | sed "s/CONNECTION_ID=//g" > sample.txt

while read actual; do

    grep -w -v $actual file1 > file1_tmp
    mv -f file1_tmp file1

done < sample.txt

这里我根据示例调整了我的代码。所以它可能也可能不起作用。

我的问题是循环重复超过1小时才能完成整个过程。

所以任何人都可以建议我如何使用diffcommsedawk或任何其他linux命令来实现相同的目标跑得快?

这里主要是我要消除这个典型的while循环。

5 个答案:

答案 0 :(得分:6)

大多数UNIX工具都是基于行的,因为您没有整行匹配,这意味着grepcommdiff不在窗口。要提取您想要的基于字段的信息awk是完美的:

$ awk 'NR==FNR{a[$2];next}!($2 in a)' file2 file1
"Connect"    CONNECT_ID="122"
"Connect"    CONNECT_ID="109"

要将结果存储回file1,您需要将输出重定向到临时文件,然后将文件移动到file1,如下所示:

$ awk 'NR==FNR{a[$2];next}!($2 in a)' file2 file1 > tmp && mv tmp file1

<强>解释

awk变量NR为每个读取的记录递增,即每个文件中的每一行。每个记录的FNR变量递增,但每个文件都会重置。

NR==FNR    # This condition is only true when reading file1
a[$2]      # Add the second field in file1 into array as a lookup table
next       # Get the next line in file1 (skips any following blocks)
!($2 in a) # We are now looking at file2 if the second field not in the look up
           # array execute the default block i.e print the line 

要修改此命令,您只需更改匹配的字段即可。在您的实际情况下,如果您想将file1中的字段1与file2中的字段4匹配,那么您可以这样做:

$ awk 'NR==FNR{a[$1];next}!($4 in a)' file2 file1

答案 1 :(得分:4)

这可能适合你(GNU sed):

sed -r 's|\S+\s+(\S+)|/\1/d|' file2 | sed -f - -i file1

答案 2 :(得分:2)

最适合这项工作的工具是join(1)。它根据每个文件的给定列中的值连接两个文件。通常它只输出两个文件中匹配的行,但它也有一个模式来输出与其他文件不匹配的文件中的行。

join要求在您加入的字段上对文件进行排序,因此要么对文件进行预排序,要么使用进程替换(bash功能 - 如示例中所示在一个命令行上执行此操作:

$ join -j 2 -v 1 -o "1.1 1.2" <(sort -k2,2 file1) <(sort -k2,2 file2)
"Connect" CONNECT_ID="122"
"Connect" CONNECT_ID="109"

-j 2表示加入两个文件的第二个字段上的文件。

-v 1表示仅输出文件1中与文件2中的任何内容不匹配的字段

-o "1.1 1.2"表示要使用文件1的第一个字段(1.1)和文件1的第二个字段(1.2)对输出进行排序。如果没有这个,join将首先输出连接列,然后输出其余列。

答案 3 :(得分:0)

您可能需要一键分析file2,并附加所有已经出现在缓存中的ID(例如内存) 比逐行扫描file1来调整缓存中的ID。

像这样的python代码:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import re

p = re.compile(r'CONNECT_ID="(.*)"')

quit_ids = set([])

for line in open('file2'):
    m = p.search(line)
    if m:
        quit_ids.add(m.group(1))


output = open('output_file', 'w')
for line in open('file1'):
    m = p.search(line)
    if m and m.group(1) not in quit_ids:
        output.write(line)
output.close()

答案 4 :(得分:0)

主要的瓶颈不是while循环,而是你重写输出文件数千次。

在您的特定情况下,您可能只能这样做:

cut -f2 file2 | grep -Fwvf - file1 >tmp
mv tmp file1

(我不认为-w的{​​{1}}选项在这里很有用,但是因为你在你的例子中有它,我保留了它。)

这预先假定grep以制表符分隔;如果没有,那你file2就好了。