我有15个文件,比如
file1.csv
a,cg2,0,0,0,21,0
a,cq1,10,0,0,0,0
a,cm2,0,19,0,0,0
...
a,ad10,0,0,0,37,0
file2.csv
d,cm1,0,3,0,0,0
d,cs2,0,32,0,0,0
d,cg2,0,0,9,0,0
...
d,az2,0,0,0,21,0
。 。 。
file15.csv
s,sd1,0,23,0,0,0
s,cw1,0,0,7,0,0
s,c23,0,0,90,0,0
...
s,cg2,0,45,0,0,0
我在每个文件中有不同的行数,我想比较所有15个文件的第二个字段,并提取所有15个文件的第二个字段共有的行。
在上述情况
输出是:
CG2
(所有15个文件的第二个字段都是常见的)
我不熟悉unix和shell脚本,请帮忙
答案 0 :(得分:3)
你想要15个文件中的每个文件的全部行,其中字段2出现在所有15个文件中吗?或者您只想要一个列在所有十五个文件中的字段2值的列表。
前者:
a,cg2,0,0,0,21,0
d,cg2,0,0,9,0,0
. . .
s,cg2,0,45,0,0,0
. . .
后者:
cg2
. . .
如果是后者,那么这应该有效
awk -F, '{arr[$2]++; if (FILENAME != prevfile) {c++; prevfile = FILENAME}} END {for (i in arr) {if (arr[i] == c) {print i}}}' file*.csv
分为多行:
awk -F, '{
arr[$2]++;
if (FILENAME != prevfile) {
c++;
prevfile = FILENAME
}
}
END {
for (i in arr) {
if (arr[i] >= c) {
print i
}
}
}' file*.csv
说明:
>=
代替==
这将起作用如果值在单个文件中出现多次)修改强>
这是一种使用双程技术打印完整匹配线的方法。这是对上述版本的修改。确保两次列出文件。
awk -F, '
FILENAME == first && flag {
exit
}
! first {
first = FILENAME
}
FILENAME != first {
flag = 1
}
{
arr[$2]++;
if (FILENAME != prevfile) {
c++;
prevfile = FILENAME
}
}
END {
# print the matching lines
do {
if ($2 in arr) {
print;
}
} while (getline);
# print the list of words
for (i in arr) {
if (arr[i] >= c) {
print i
}
}
}' file*.csv file*.csv
它取决于第一个组中的第一个文件与第二个组中的第一个文件同名。使用类似于我所展示的globbing将处理该要求。
它打印匹配的行(不分组),然后打印单词列表。如果您只想要其中一个,请注释掉或删除您不想要的循环(do/while
或for
)。
如果只打印整行,可以将输出通道输出到:
sort -t , -k2,2
让他们分组。
仅将单词列表用于:
sort
将它们放在相同的顺序中以便于比较。
答案 1 :(得分:1)
有趣的问题。
完全用Bash完成的一种方法如下。
您需要调用的一件事是join -t ',' -1 2 -2 2 file1 file2
加入两个文件的第二列。但是,在加入之前,您必须对第二列进行排序。
在for循环中进行连续连接,因为join
只接受两个文件作为参数。
附录
这是一个显示连续加入的小记录。我认为你可以很容易地调整它。
$ cat 1.csv
a,b,c,d
e,f,g,h
i,j,k,l
$ cat 2.csv
7,5,4,3
3,b,s,e
2,f,5,5
$ cat 3.csv
4,5,6,7
0,0,0,0
1,b,4,4
$ join -t ',' -1 2 -2 2 1.csv 2.csv | cut -f 1 -d ',' > temp
$ cat temp
b
f
$ join -t ',' -2 2 temp 3.csv | cut -f 1 -d ','
b
第一个连接(在前两个文件上)在结果的第一列中生成连接值。因此,当您加入file3,file4,file5等时,您将使用您生成的结果的第一列,这就是您只需要-2选项的原因。为了保持高效,每次进行连接时,请始终删除除第一列之外的所有列。