如何在bash中比较和连接巨大csv文件中的相同行



我有以下.csv文件(大小巨大,数百MB到GB,几列~20,未排序,用","分隔):

name1,address1,town1,zip1,....,category1
name2,address2,town2,zip2,....,category2
name3,address3,town3,zip3,....,category3_1
name3,address3,town3,zip3,....,category3_2
name3,address3,town3,zip3,....,category3_3
name4,address4,town4,zip4,....,category4_1
name4,address4,town4,zip4,....,category4_2
name4,address4,town4,zip4,....,category4_3
name4,address4,town4,zip4,....,category4_4
name5,address5,town5,zip5,....,category5

如果行相同,但仅在类别上不同,则我需要将行连接到一行,并将这些类别放在带有";"分隔符的最后一列,例如:

name1,address1,town1,zip1,....,category1
name2,address2,town2,zip2,....,category2
name3,address3,town3,zip3,....,category3_1;category3_2;category3_3
name4,address4,town4,zip4,....,category4_1;category4_2;category4_3;category4_4
name5,address5,town5,zip5,....,category5

我在阅读时用尝试过。。。;请务必阅读。。。done<文件,但这只是按2行读取每个文件,而不是比较每一行。还试图将类别信息保存到数组中并创建合并的类别列,但在某行脚本中,它只是停止了按我想要的方式进行解析。用awksed完成这项工作会很好,因为read在读取包含大量列的大文件时确实很慢,但如果有更好的方法用其他语言完成这项任务,我也可以。非常感谢!

两个答案:

外壳+sed

你可以在这种(特殊)情况下使用sed:

嗯,太快了!我错了!

$ sed -e ':;N;s/^(([^,]+,){5})(.*)*n1/13;/;t' file.csv

)

$ sed -e ':a;$!N;s/^(([^,]+,){5})(.*)*n1/13;/;ta;P;D;$!ba' file.csv

用于检索列数(-1),也就是分隔符数:

read line <file.csv
cols="${line//,}"
cols=$[${#line}-${#cols}]
sed -e "
    :a;
     $!N;
     s/^(([^,]+,){$cols})(.*)*n1/13;/;
     ta;
     P;
     D;
     $!ba
  " file.csv
name1,address1,town1,zip1,....,category1
name2,address2,town2,zip2,....,category2
name3,address3,town3,zip3,....,category3_1;category3_2;category3_3
name4,address4,town4,zip4,....,category4_1;category4_2;category4_3;category4_4
name5,address5,town5,zip5,....,category5

仅限最后一个字段

基于最后一个逗号,有一种更简单的方法:

sed -e ":;$!N;s/^(.*,)([^,]*)*n1/12;/;t;P;D;$!b" file.csv

(用于在线路末端鞭打不需要的CR

sed -e ':;$!N;s/o015//g;s/^(.*,)([^,]*)*n1/12;/;t;P;D;$!b'

)

纯bash(无叉)

这可以使用纯bash来完成(使用dash和busybox也可以!),但可能更适合小文件:

while read line;do
    if [ "${line%,*}" = "${last%,*}" ];then
        last="$last;${line##*,}"
    else
        echo "$last"
        last="$line"
    fi
done < file.csv
echo "$last"
name1,address1,town1,zip1,....,category1
name2,address2,town2,zip2,....,category2
name3,address3,town3,zip3,....,category3_1;category3_2;category3_3
name4,address4,town4,zip4,....,category4_1;category4_2;category4_3;category4_4
name5,address5,town5,zip5,....,category5

注意:不需要知道列数,因为这是基于最后一个逗号

最新更新