【问题标题】:How to check if a list of strings are present in two separate files如何检查两个单独的文件中是否存在字符串列表
【发布时间】:2012-07-10 05:34:02
【问题描述】:

我有两个文件,“文件 A”是 IP 地址列表,对应的 MAC 地址位于同一行。 “文件 B”是仅 MAC 地址的列表。我需要比较这两个文件并列出文件 A 中没有在文件 B 中找到 MAC 地址的行。

文件 A:

172.0.0.1 AA:BB:CC:DD:EE:01
172.0.0.2 AA:BB:CC:DD:EE:02
172.0.0.3 AA:BB:CC:DD:EE:03

文件 B:

AA:BB:CC:DD:EE:01
AA:BB:CC:DD:EE:02

所以输出应该是:

172.0.0.3 AA:BB:CC:DD:EE:03

我正在寻找 sed、awk、grep、python 或任何能够为我提供所需文件的解决方案。

【问题讨论】:

  • 您的文件真的每行开头都有美元符号吗?如果他们不这样做会更容易。
  • 它们没有美元符号。我已经编辑了这个问题以反映这一点。谢谢。
  • 太棒了。然后查看下面的fgrep 答案。

标签: python text sed awk compare


【解决方案1】:

您的输入是否真的在每一行的开头都有一个美元符号,或者这是您问题的格式怪癖?如果你可以摆脱美元符号,那么你可以使用这个:

fgrep -v -f fileb filea

【讨论】:

  • 这很棒。到目前为止最好的答案(在我看来)。
  • 这行得通。我不得不更改其中一个输入文件以使大小写一致。我用这个:tr '[:upper:]' '[:lower:]' < macs > macslower
  • 您也可以将-i 添加到fgrep 以进行不区分大小写的匹配。
【解决方案2】:
with open('filea','r') as fa:    
    with open('fileb','r') as f:
        MACS=set(line.strip() for line in f)

    for line in fa:
        IP,MAC=line.split()
        if MAC not in MACS:
            print (line.strip())

【讨论】:

  • 如果 filea 不可读,您可以使用单个 with-statement 来避免创建 set()。输出中不应有$
  • @J.F.Sebastian :我不喜欢在同一个with 语句中包含多个内容。对我来说,它杂乱无章,难以阅读。但你是对的。如果我嵌套我的 with 语句,那么我可以避免你描述的场景。更新。还去掉了输出中的 $。
【解决方案3】:
#!/usr/bin/env python
with open('fileb') as fileb, open('filea') as filea:
    macs = set(map(str.strip, fileb))
    for line in filea:
        ip_mac = line.split()
        if len(ip_mac) == 2 and ip_mac[1] not in macs:
           print(" ".join(ip_mac))

【讨论】:

  • line.split()line.split(' ') 稍微通用一些(例如,如果 IP 和 MAC 被 2 个空格分隔,这将阻塞)。此外,这假设 fileb 中的行上没有额外的空格。
  • @mgilson: .split() 去除换行符。我同意这个版本是“空白易碎”。
  • @mgilson:我让它对不同的空格不那么敏感了
  • 现在我很满意 (+1) :)
  • 我已经删除了 '$' 处理(问题已更新)并且对无效输入更加稳健
【解决方案4】:

Python:

macs = set(line.strip() for line in open('fileb'))
with open('filea') as ips:
    for line in ips:
        ip,mac = line.split()
        if mac not in macs:
            print line

编辑:好的,所以每个人都发布了相同的 python 答案。我也先接触python,但是 傻眼

awk 'NR == FNR {fileb[$1];next} !($2 in fileb)' fileb filea

EDIT2:OP 从行中删除了前导 $,因此 python 和 awk 发生变化,并且 fgrep 可以发挥作用。

fgrep -v -f fileb filea

【讨论】:

  • awk 解决方案似乎返回了 fileA 的全部内容。虽然 python 解决方案因语法错误而抱怨我。 '回溯(最近一次调用最后一次):文件“pycompare.py”,第 4 行,在 ip,mac = line.split() ValueError: need more than 1 value to unpack'
  • @cpashia 看起来不错,但如果 a 和 b 颠倒,我会得到你的结果。在 awk fileb 中首先出现(mac 地址)。我使用了您的原始文件名。
【解决方案5】:
with open(FILEB) as file1,open(FILEA) as file2:
file1={mac.strip() for mac in file1}
file2={line.split()[1]:line.split()[0] for line in file2}
    for x in file2:
        if x not in file1:
            print("{0} {1}".format(file2[x],x))

输出:

172.0.0.2 AA:BB:CC:DD:EE:05
172.0.0.4 AA:BB:CC:DD:EE:06
172.0.0.6 AA:BB:CC:DD:EE:03
172.0.0.66 AA:BB:CC:DD:EE:0E

【讨论】:

  • rstrip().split() 完全等同于strip()
  • mgilson 的意思是 .split() 忽略尾随空格
  • if x not in file1 在你的情况下是 O(n) 。使用 set() 而不是列表。在这种情况下不需要字典。代码不可读
  • @AshwiniChaudhary -- J.F.Sebastian 是对的。我的意思是rstrip().split() 等同于split()。对不起。
【解决方案6】:

使用awk 的一种方式。它将来自fileB 的 MAC 保存在一个数组中,并且对于fileA 的每个第二个字段,在数组中检查它,只有在找不到时才打印。

awk '
    FNR == NR {
        data[ $0 ] = 1;
        next;
    }
    NFR < NR && !($2 in data)
' fileB fileA

输出:

172.0.0.3 AA:BB:CC:DD:EE:03

【讨论】:

  • 这似乎返回了 fileA 的全部内容。
  • +1,但您应该使用mac = $0 或仅使用data[ $0 ] = 1 而不是substr,并且第二个块可以简化为NFR &lt; NR &amp;&amp; !($2 in data)
  • @WilliamPursell:谢谢。我根据您的建议编辑了答案。 Cpashia 编辑了问题,但就在 IP 将印记作为第一个字符之前,我使用 substr 函数将其删除。所以我意识到之前的评论说该程序不起作用。已经修好了。
【解决方案7】:

Python 是最简单的。将文件 B 读入字典,然后遍历文件 A 并在字典中查找匹配项。

【讨论】:

    【解决方案8】:

    我可以编写一个 Java 示例,您可以将其翻译成任何您想要的语言

    import java.io.*;
    import java.util.*;
    class Macs {
        public static void main(String...args)throws Exception {
            Set<String> macs = loadLines("macs.txt");
            Set<String> ips = loadLines("ips.txt");
    
            for(String raw : ips) {
                String[] tokens = raw.split("\\s"); // by space
                String ip = tokens[0];
                String mac = tokens[1];
                if(!macs.contains(mac))
                    System.out.println(raw);
            } 
        }
    
        static Set<String> loadLines(String filename) throws Exception {
            Scanner sc = new Scanner(new File(filename));
            Set<String> lines = new HashSet<String>();
            while(sc.hasNextLine()) {
                // substring(1) removes leading $
                lines.add(sc.nextLine().substring(1).toLowerCase());
            }
            return lines;
        }
    }
    

    将此输出重定向到文件将为您提供结果。

    用下面的输入文件

    macs.txt

    $AA:BB:CC:DD:EE:01
    $AA:BB:CC:DD:EE:02
    $AA:BB:CF:DD:EE:09
    $AA:EE:CF:DD:EE:09
    

    ips.txt

    $172.0.0.1 AA:BB:CC:DD:EE:01
    $172.0.0.2 AA:BB:CC:DD:EE:02
    $172.0.0.2 AA:BB:CC:DD:EE:05
    $172.0.0.66 AA:BB:CC:DD:EE:0E
    $172.0.0.4 AA:BB:CC:DD:EE:06
    $172.0.0.5 AA:BB:CF:DD:EE:09
    $172.0.0.6 AA:BB:CC:DD:EE:03
    

    结果:

    c:\files\j>java Macs
    172.0.0.6 aa:bb:cc:dd:ee:03
    172.0.0.66 aa:bb:cc:dd:ee:0e
    172.0.0.2 aa:bb:cc:dd:ee:05
    172.0.0.4 aa:bb:cc:dd:ee:06
    

    【讨论】:

      【解决方案9】:

      这可能对你有用(GUN sed);

      sed 's|.*|/&/Id|' fileb | sed -f - filea
      

      【讨论】:

        猜你喜欢
        • 2015-12-24
        • 2017-02-28
        • 2012-05-25
        • 1970-01-01
        • 1970-01-01
        • 2018-06-06
        • 1970-01-01
        • 2016-12-11
        • 1970-01-01
        相关资源
        最近更新 更多