我有三种不同的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。
答案 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
注意第三栏。如果该行未出现在两个文件中,则为空。所以这解决了你的一半问题。然后,您可以尝试使用sed
或awk
更改最后一列,如果它是非空的,则根据您的要求使用是/否。当然,没有什么能阻止你再次针对第三个文件运行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)
包含join
和sort
的{{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
过滤,用逗号替换冒号,产生所需的输出。