检查file2.csv中是否存在来自file1.csv的模式列表,并更改file2.csv中的记录

时间:2019-01-17 10:20:33

标签: bash csv unix awk sed

我有2个文件file1.csv和file2.csv

file1.csv仅包含100列的1列。

aaa
ddd
fff
ggg

file2.csv包含5个具有数千行的字段。

aaa,2,3,4,
aaa,2,3,4, 
bbb,2,3,4,
ccc,2,3,4, 
ccc,2,3,4, 
ddd,2,3,4, 
ddd,2,3,4,
ddd,2,3,4,  
eee,2,3,4, 
fff,2,3,4, 
ggg,2,3,4, 
hhh,2,3,4, 
hhh,2,3,4,   

我的任务是检查file1.csv中存在的col1是否与fil2.csv中的col1相匹配,然后将file2.csv中的第5列更改为Y

所需的输出

aaa,2,3,4,Y
aaa,2,3,4,Y 
bbb,2,3,4, 
ccc,2,3,4, 
ccc,2,3,4, 
ddd,2,3,4,Y
ddd,2,3,4,Y
ddd,2,3,4,Y  
eee,2,3,4, 
fff,2,3,4,Y 
ggg,2,3,4,Y 
hhh,2,3,4, 
hhh,2,3,4, 

我尝试过的是

for i in $(cat file1.csv); do awk -F "," '$1==$i{$5="Y"}1' OFS="," file2.csv ; done

但是我只得到匹配的记录,而没有得到不匹配的记录。

有没有更好的方法可以在UNIX中使用awk,sed或其他常用实用程序来实现这一目标。

编辑: 用明确的示例更新问题

2 个答案:

答案 0 :(得分:1)

不需要那样做,只需awk读取两个文件就可以了:

awk -F, 'NR==FNR{a[$1]++;next;}a[$1]{$5="Y"}1' file1.csv file2.csv

不确定标题和第二行是否是您的解释方式,是否想摆脱它们:

awk -F, 'NR==FNR{a[$1]++;next;}a[$1]{$5="Y"}FNR>2' file1.csv file2.csv

请注意,如果file1.csv可以为空,则应将NR==FNR更改为其他文件检查方法,例如GNU awk的ARGIND==1FILENAME=="file1.csv"等。

如果要处理大量数据,请将a[$1]++更改为a[$1]=1会稍微提高速度。
另外,如果要保留标题(或第二行),则最好在aFNR>1时开始更改数组FNR>2。自己完善命令,我相信您已经明白了;)

NR==FNR表示第一个文件,因为NR表示现在总共 R 个折线的 N 个数字,而FNR表示当前的< strong> F ile的 R 折线的数量。
a是一个实际将$1保存为键的数组。
next跳过其他程序块的执行。

如果NR==FNR为false,则表示它不是第一个文件,因此不会执行第一个块。
(您也可以在块之前使用NR>FNR来指定它,但是由于我在next块中使用了NR==FNR,所以没有必要。)
然后使用其他指令,a[$1]判断键是否存在于数组a中(通过引用该值,从字面上检查key exists实际上应该是$1 in a),如果存在,则更改$ 5。
最后一个1是要指定一个真值,它是{print}的快捷方式。
(由于表达式没有块,因此将隐含{print},并且在计算为true始终为1的先前表达式时,将执行块。)

答案 1 :(得分:0)

您可以尝试Perl解决方案

$ perl -F, -lane 'BEGIN {%kv=map{chomp;$_=>1} qx(cat file1.csv) } print "$_", $kv{$F[0]}? "Y" : "" ' file2.csv
aaa,2,3,4,Y
aaa,2,3,4,Y
bbb,2,3,4,
ccc,2,3,4,
ccc,2,3,4,
ddd,2,3,4,Y
ddd,2,3,4,Y
ddd,2,3,4,Y
eee,2,3,4,
fff,2,3,4,Y
ggg,2,3,4,Y
hhh,2,3,4,
hhh,2,3,4,

$ cat file1.csv
aaa
ddd
fff
ggg

$ cat file2.csv
aaa,2,3,4,
aaa,2,3,4,
bbb,2,3,4,
ccc,2,3,4,
ccc,2,3,4,
ddd,2,3,4,
ddd,2,3,4,
ddd,2,3,4,
eee,2,3,4,
fff,2,3,4,
ggg,2,3,4,
hhh,2,3,4,
hhh,2,3,4,

$