用于比较两个不同文件中的字符串的脚本

时间:2011-12-08 18:39:35

标签: python perl bash

我是stackoverflow和脚本的新手。我正在寻找帮助以开始编写脚本,而不一定要找人写。

这是我的所作所为: File1.csv - 包含一些信息,我只对MAC地址感兴趣。 File2.csv - 有一些不同的信息,但也包含MAC地址。

我需要一个脚本来解析来自file1.csv的MAC地址,并在file2.csv中显示任何 MAC地址时记录报告。

问题:

  1. 我使用的语言有哪些提示,最好是perl,python或bash?

  2. 任何人都可以建议一些所需逻辑的结构(即使只是在伪代码中)?

  3. 更新

    使用@Adam Wagner的方法,我非常接近!

    import csv
    #Need to strip out NUL values from .csv file to make python happy
    class FilteredFile(file):
            def next(self):
                    return file.next(self).replace('\x00','').replace('\xff\xfe','')
    
    reader = csv.reader(FilteredFile('wifi_clients.csv', 'rb'), delimiter=',', quotechar='|')
    s1 = set(rec[0] for rec in reader)
    
    inventory = csv.reader(FilteredFile('inventory.csv','rb'),delimiter=',')
    s2 = set(rec[6] for rec in inventory)
    
    shared_items = s1.intersection(s2)
    print shared_items
    

    这总是输出:(即使我教.csv文件具有匹配的MAC地址)

      

    组([])

    csv文件的内容

      

    wifi_clients.csv

         
        

    macNames,第一次看到,上次见过,Power,#packets,BSSID,Probed ESSID

      
         

    inventory.csv

         
        

    名称,制造商,设备类型,型号,序列号,IP地址,MAC地址,......

      

4 个答案:

答案 0 :(得分:5)

这是我采取的方法:

  1. 迭代每个csv文件(python有一个方便的csv模块来完成此操作),捕获mac-address并将其放入一个集合(每个文件一个)。再一次,python有一个很好的内置set类型。 Here's a good example of using the csv module当然还有the docs

  2. 接下来,您可以获取set1(file1)和set2(file2)的intersection。这将显示存在于文件1和2中的mac-address。

  3. 示例(在python中):

    s1 = set([1,2,3])  # You can add things incrementally with "s1.add(value)"
    s2 = set([2,3,4])
    
    shared_items = s1.intersection(s2)
    print shared_items
    

    哪个输出:

    set([2, 3])
    

    记录这些共享项目可以通过打印(然后将输出重定向到文件),使用logging模块,直接保存到文件中完成。

    我不确定你正在寻找的答案有多深入,但这应该让你开始。

    更新:CSV /设置使用示例

    假设你有一个文件“foo.csv”,它看起来像这样:

    bob,123,127.0.0.1,mac-address-1
    fred,124,127.0.0.1,mac-address-2
    

    构建集合的最简单方法是:

    import csv
    
    set1 = set()
    for record in csv.reader(open('foo.csv', 'rb')):
        user, machine_id, ip_address, mac_address = record
        set1.add(mac_address)
        # or simply "set1.add(record[3])", if you don't need the other fields.
    

    显然,每个文件都需要这样的东西,所以你可能想把它放在一个函数中,以使生活更轻松。

    最后,如果你想采用那种不那么冗长但更酷的python方式,你也可以构建这样的集合:

    csvfile = csv.reader(open('foo.csv', 'rb'))
    set1 = set(rec[3] for rec in csvfile)   # Assuming mac-address is the 4th column.
    

答案 1 :(得分:1)

我强烈建议python这样做。

'因为你没有给出csv文件的结构,我只能展示一个框架:

def get_MAC_from_file1():
    ... parse the file to get MAC
    return a_MAC_list
def get_MAC_from_file2():
    ... parse the file to get MAC
    return a_MAC_list
def log_MACs():
    MAC_list1, MAC_list2 = get_MAC_from_file1(), get_MAC_from_file2()
    for a_MAC in MAC_list1:
        if a_MAC in MAC_list2:
            ...write your logs

如果数据集很大,请使用dict或set而不是list和intersect操作。但是因为它是MAC地址,我猜你的数据集并不是那么大。因此,保持脚本易于阅读是最重要的事情。

答案 2 :(得分:1)

Awk非常适合这个

{
   mac = $1  # assuming the mac addresses are in the first column
   do_grep = "grep " mac " otherfilename" # we'll use grep to check if the mac address is in the other file
   do_grep | getline mac_in_other_file  # pipe the output of the grep command into a new variable
   close(do_grep)  # close the pipe
   if(mac_in_other_file != ""){     # if grep found the mac address in the other file
     print mac > "naughty_macs.log"  # append the mac address to the log file
   }
}

然后你在第一个文件上运行它: awk -f logging_script.awk mac_list.txt

(这段代码未经测试,我不是最好的awk黑客,但它应该给出一般的想法)

答案 3 :(得分:1)

为了示例目的,生成2个看起来像你的文件。

File1中:

for i in `seq 100`; do 
   echo -e "user$i\tmachine$i\t192.168.0.$i\tmac$i"; 
done > file1.csv

File2(包含编号为1-200的“mac地址”的随机条目)

for j in `seq 100`; do 
    i=$(($RANDOM % 200)) ; 
    echo -e "mac$i\tmachine$i\tuser$i"; 
done > file2.csv

最简单的方法是使用join命令并在适当的字段上进行连接。这种方法的优点是两个文件中的字段都可以在输出中使用。

根据上面的示例文件,命令如下所示:

join -1 4 -2 1 <(sort -k4 file1.csv)  <(sort -k1 file2.csv)

join需要输入按您匹配的字段排序,这就是排序的原因(-k告诉使用哪个列) 如果第一个文件中的第4列与第二个文件中的第1列相等,则上面的命令将file1.csv中的行与来自file2.csv的行匹配。

如果您只需要特定字段,则可以为join命令指定输出格式:

join -1 4 -2 1 -o1.4 1.2 <(sort -k4 file1.csv)  <(sort -k1 file2.csv)

这将只打印第一个文件中的mac地址和机器字段。

如果您只需要匹配的mac地址列表,可以使用uniq或sort -u。由于连接输出将按mac排序,因此uniq更快。但如果您需要另一个字段的唯一列表,请排序-u更好。

如果您只需要匹配的mac地址,grep可以接受文件中的模式,并且您可以使用cut来仅提取第四个字段。

fgrep -f<(cut -f4 file1.csv) file2.csv

以上将列出file2.csv中包含来自file1的mac地址的所有行 请注意,我正在使用不进行模式匹配的fgrep。此外,如果file1很大,这可能比第一种方法慢。此外,它假定mac仅存在于file2的field1中,而其他字段不包含mac地址。 如果你只需要mac,你可以在fgrep上使用-o选项但是有没有它的grep变种,或者你可以通过cut管道输出,然后排序-u

fgrep -f<(cut -f4 file1.csv) file2.csv | cut -f1 | sort -u

这将是bash方式。

上面已经显示了Python和awk提示,我将对perl进行一次尝试:

#!/usr/bin/perl -w

use strict;

open F1, $ARGV[0];
my %searched_mac_addresses = map {chomp; (split /\t/)[3] => 1 } <F1>;
close F1;

open F2, $ARGV[1];

while (<F2>) {
    print if $searched_mac_addresses{(split "\t")[0]}
}

close F2

首先,您创建一个包含第一个文件中所有mac地址的字典:

my %searched_mac_addresses = map {chomp; (split /\t/)[3] => 1 } <F1>;
  • 从file1
  • 读取所有行
  • chomp删除行尾
  • split基于制表符拆分行,您可以根据需要使用更复杂的正则表达式
  • ()围绕分裂强制数组上下文
  • [3]选择第四个字段
  • map为数组的所有元素运行一段代码
  • =&GT;生成一个字典(在perl的术语中使用哈希)元素而不是数组

然后你逐行读取第二个文件,并检查上面的字典中是否存在mac:

while (<F2>) {
    print if $searched_mac_addresses{(split "\t")[0]}
}
  • while()将读取文件F2,并将每行放在$ _ variable
  • 不带任何参数的打印输出默认变量$ _
  • if if post post a instruction
  • 字典元素可以通过{}
  • 访问 默认情况下,
  • 拆分会拆分$ _默认变量