Python 如何检查字符串列表是否存在于两个单独的文件中

Python 如何检查字符串列表是否存在于两个单独的文件中,python,text,sed,awk,compare,Python,Text,Sed,Awk,Compare,我有两个文件,“文件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:D

我有两个文件,“文件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或任何能提供我想要的文件的解决方案。

python是最简单的。将文件B读入字典,然后浏览文件a并在字典中查找匹配项。

我可以制作一个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;
    }
}
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
输出:

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

单向使用
awk
。它将
fileB
中的MAC保存在一个数组中,并且对于
fileA
的每秒钟字段,在数组中检查它,只有在找不到时才打印

awk '
    FNR == NR {
        data[ $0 ] = 1;
        next;
    }
    NFR < NR && !($2 in data)
' fileB fileA
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

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

fgrep -v -f fileb filea
这可能对你有用(枪塞德)


rstrip().split()
完全等同于
strip()
。mgilson的意思是
。split()
忽略尾随空格
,如果在您的情况下,file1中没有x
是O(n)。使用
set()
而不是list。在这种情况下不需要词典。代码是unreadable@AshwiniChaudhary--塞巴斯蒂安是对的。我想说的是
rstrip()。split()
相当于
split()
。很抱歉。
line.split()
line.split(“”)
更一般(例如,如果IP和MAC被两个空格分隔,这将阻塞)。此外,这还假设文件B中的行上没有多余的空格。@mgilson:
.split()
删除换行符。我同意这个版本是“空白脆弱的”。@mgilson:我已经使它对不同的空白不那么敏感了现在我很高兴(+1):)我已经删除了“$”处理(问题被更新),并且对无效输入更加健壮。如果文件a不可读,你可以使用一个
with
-语句来避免创建
集()
。输出中不应该有
$
。@J.F.Sebastian:我不喜欢在同一
语句中有多个东西。对我来说,它杂乱无章,难以阅读。但你是对的。如果我用
语句嵌套我的
,那么我可以避免您描述的场景。更新。也去掉了输出中的美元。你的文件真的在每行的开头都有美元符号吗?如果他们没有,那就容易多了。他们没有美元符号。我对问题进行了编辑,以反映这一点。谢谢,太好了。然后查看下面的
fgrep
答案。这很好。到目前为止,这是最好的答案(在我看来)。这是有效的。我必须更改其中一个输入文件以使案例一致。我使用了这个:
tr'[:upper:''[:lower:'macsloor
您也可以将
-I
添加到
fgrep
以进行不区分大小写的匹配。这似乎返回文件a+1的全部内容,但您应该使用
mac=$0
或只使用
数据[$0]=1,第二个块可以简化为
NFR
@williampersell:谢谢。我用你的建议编辑了答案。Cpashia编辑了这个问题,但就在IPs将sigil作为第一个字符之前,我使用
substr
函数删除了它。所以我意识到前面的评论说这个程序不起作用。已修复。awk解决方案似乎返回fileA的全部内容。而python解决方案却向我抱怨语法错误。”回溯(最后一次调用):文件“pycompare.py”,第4行,在ip中,mac=line.split()value错误:需要超过1个值才能解包'@cpashia看起来不错,但如果a和b颠倒,我会得到你的结果。在awk中,fileb是第一位的(mac地址)。我用了你原来的文件名。
172.0.0.3 AA:BB:CC:DD:EE:03
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
awk 'NR == FNR {fileb[$1];next} !($2 in fileb)' fileb filea
fgrep -v -f fileb filea
fgrep -v -f fileb filea
sed 's|.*|/&/Id|' fileb | sed -f - filea