Bash脚本用于查找来自多个csv文件的匹配行,并从中创建报告

时间:2013-07-03 23:36:05

标签: bash shell

我有三种不同的CSV文件。格式如下:

domain1.csv

name1,lastname1
name2,lastname2
name3,lastname3

domain2.csv

name1,lastname1
name6,lastname6
name3,lastname3

domain3.csv

name1,lastname1
name4,lastname4
name3,lastname3

现在基于这三个文件,我需要像这样创建报告

name,lastname,domain1,domain2,domain3
name1,lastname1,yes,yes,yes
name2,lastname2,yes,no,no
name3,lastname3,yes,yes,yes
name4,lastname4,no,no,yes
name6,lastname6,no,yes,no

基本上这个报告只能使用一个脚本,该脚本可以在每个文件中逐个读取行,并在其他两个文件中找到该行,并通过匹配name和lastname列来创建报告。但我是shell脚本的全新手。有人能帮我吗。我正在使用bash。

3 个答案:

答案 0 :(得分:1)

你真的不想用bash写这个,意思是while循环和逐行比较,因为那太痛苦和缓慢。 shell有很多工具可用。在这种情况下派上用场的一个称为join(关系数据库上下文:由于-a1 -a2,这将是笛卡尔积或交叉连接)。如果您的.csv文件已排序(请参阅shell命令sort

join -t, -a1 -a2 dom1.csv dom2.csv

给出

name1,lastname1,lastname1

name2,lastname2

name3,lastname3,lastname3

name6,lastname6

注意第三栏。如果该行未出现在两个文件中,则为空。所以这解决了你的一半问题。然后,您可以尝试使用sedawk更改最后一列,如果它是非空的,则根据您的要求使用是/否。当然,没有什么能阻止你再次针对第三个文件运行join,并按摩输出以包含是/否。

答案 1 :(得分:1)

awk是一种迷你语言,是大多数类Unix操作系统的标准配置,可以让您轻松解决这类问题。

awk '{ names[$0] = (names[$0] "," FILENAME) }
     END { print "name,lastname,domain1,domain2,domain3"
           for( elt in names ) {
             printf "%s,%s,%s,%s\n", elt,
                                     index( names[elt], "domain1.csv" ) ? "yes" : "no",
                                     index( names[elt], "domain2.csv" ) ? "yes" : "no",
                                     index( names[elt], "domain3.csv" ) ? "yes" : "no"
           }
         }' domain*.csv | sort

上面的脚本逐行解析每个文件,并使用nameN,lastnameN构建一个关联数组作为索引,并将它们找到的文件名(以逗号分隔)作为值。然后它遍历关联数组并打印每个索引,后跟“是”或“否”字符串,具体取决于数组的值是否包含每个文件名。

答案 2 :(得分:0)

包含joinsort的{​​{1}}命令是所需的主要工具。假设sed未出现在原始数据中。要记录文件中是否存在行,我们需要文件中的:字段;如果没有匹配,我们会yes提供join。使用no的进程替换,我们可以写:

bash

$ sed 's/$/:yes/' domain1.csv | sort | > join -t: -a 1 -a 2 -e no -o 0,1.2,2.2 - <(sed s'/$/:yes/' domain2.csv | sort) | > join -t: -a 1 -a 2 -e no -o 0,1.2,1.3,2.2 - <(sed 's/$/:yes/' domain3.csv | sort) | > sed 's/:/,/g' name1,lastname1,yes,yes,yes name2,lastname2,yes,no,no name3,lastname3,yes,yes,yes name4,lastname4,no,no,yes name6,lastname6,no,yes,no $ sed组合(三次)将sort添加到文件中并对名称进行排序。连接几乎是对称的。 :yes指定字段分隔符是冒号; -t:-a 1表示当文件中没有匹配项时,该行仍将包含在输出中; -a 2表示如果文件中没有匹配项,则在输出中生成-e no;并且no选项指定输出列。对于第一次连接,-o输出是连接列(-o 0,1.2,2.2),然后是两个文件中的第二列(0)。第二个连接在输入中有3列,因此它指定yes。参数-o 0,1.2,1.3,2.2本身就意味着“读取标准输入”。 -表示法是“进程替换”,其中文件名(通常为<(...))提供给/dev/fd/NN命令,它包含括号内的命令输出。然后,输出再次通过join过滤,用逗号替换冒号,产生所需的输出。