awk 根据列合并行

SVR*_*SVR 3 awk

想要将基于第一列的行合并$1到行中并格式化输出。打印时需要生成 headerMax Unique count of first field. 例如,安哥拉出现 count=3 ,巴西出现 count=5 ,赞比亚出现 count=1 。字段 $1 的最大唯一计数为 5 ,因此需要打印标题 5 次才能为所有字段提供正确的标题。

打印输出时,要保留original input file订单行。我的实际输入文件曾经有所不同,例如 10 个字段、12 个字段等。

输入.csv

Country,Network,Details,Amount
Angola,voda,xxx,10
Angola,at&t,xxx,20
Angola,mtn,xxx,30
Brazil,voda,yyy,40
Brazil,voda,yyy,50
Brazil,at&t,yyy,60
Brazil,mtn,yyy,70
Brazil,voda,yyy,80
Zambia,tcl,zzz,90
Run Code Online (Sandbox Code Playgroud)

所需输出.csv

Country,Network,Details,Amount,Country,Network,Details,Amount,Country,Network,Details,Amount,Country,Network,Details,Amount,Country,Network,Details,Amount
Angola,voda,xxx,10,Angola,at&t,xxx,20,Angola,mtn,xxx,30
Brazil,voda,yyy,40,Brazil,voda,yyy,50,Brazil,at&t,yyy,60,Brazil,mtn,yyy,70,Brazil,voda,yyy,80
Zambia,tcl,zzz,90
Run Code Online (Sandbox Code Playgroud)

目前,我正在使用以下两个命令来获取所需的输出,并每次根据实际输入文件中的字段数量手动更改计数。

步骤1

awk 'BEGIN { while (count++<5) header=header "Country,Network,Details,Amount,"; print header }' > output.csv
Run Code Online (Sandbox Code Playgroud)

第2步

awk -F, '
    /.+/{
        if (!($1 in Val)) { Key[++i] = $1; }
        Val[$1] = Val[$1]  $0 ",";
    }
    END{
        for (j = 1; j <= i; j++) {
            print(Val[Key[j]] );
        }
    }' input.csv >> output.csv
Run Code Online (Sandbox Code Playgroud)

寻找您的建议...

Aks*_*gde 5

awk单线:

awk 'BEGIN{FS=OFS=","}FNR==1{n=$0;next}{a[$1]=($1 in a ? a[$1] OFS:"")$0; if(!($1 in b)){o[++i]=$1}; b[$1]++; mx=mx>b[$1]?mx:b[$1] }END{for(i=1; i<=mx; i++)printf("%s%s",n,i==mx?RS:OFS); for(i=1; i in o; i++)print a[o[i]]}' infile
Run Code Online (Sandbox Code Playgroud)

输入:

$ cat infile
Country,Network,Details,Amount
Angola,voda,xxx,10
Angola,at&t,xxx,20
Angola,mtn,xxx,30
Brazil,voda,yyy,40
Brazil,voda,yyy,50
Brazil,at&t,yyy,60
Brazil,mtn,yyy,70
Brazil,voda,yyy,80
Zambia,tcl,zzz,90
Run Code Online (Sandbox Code Playgroud)

输出:

$ awk 'BEGIN{FS=OFS=","}FNR==1{n=$0;next}{a[$1]=($1 in a ? a[$1] OFS:"")$0; if(!($1 in b)){o[++i]=$1}; b[$1]++; mx=mx>b[$1]?mx:b[$1] }END{for(i=1; i<=mx; i++)printf("%s%s",n,i==mx?RS:OFS); for(i=1; i in o; i++)print a[o[i]]}' infile
Country,Network,Details,Amount,Country,Network,Details,Amount,Country,Network,Details,Amount,Country,Network,Details,Amount,Country,Network,Details,Amount
Angola,voda,xxx,10,Angola,at&t,xxx,20,Angola,mtn,xxx,30
Brazil,voda,yyy,40,Brazil,voda,yyy,50,Brazil,at&t,yyy,60,Brazil,mtn,yyy,70,Brazil,voda,yyy,80
Zambia,tcl,zzz,90
Run Code Online (Sandbox Code Playgroud)

更好的可读性:

awk 'BEGIN{
            FS=OFS=","
     }
     FNR==1{
            n=$0;
            next
     }
     {
           a[$1]=($1 in a ? a[$1] OFS:"")$0;
           if(!($1 in b)){ o[++i]=$1 }; 
           b[$1]++; 
           mx=mx>b[$1]?mx:b[$1] 
     }
    END{
           for(i=1; i<=mx; i++)
               printf("%s%s",n,i==mx?RS:OFS); 

            for(i=1; i in o; i++)
                print a[o[i]]
     }' infile
Run Code Online (Sandbox Code Playgroud)

评论:

想知道在哪里更改代码,仅第一次在输出中打印“国家/地区”,如果我不需要第二次、第三次打印相同的国家/地区名称

$ awk 'BEGIN{FS=OFS=","}FNR==1{n=$0;next}{a[$1]=($1 in a ? a[$1] OFS substr($0,index($0,",")+1) : $0); if(!($1 in b)){o[++i]=$1}; b[$1]++; mx=mx>b[$1]?mx:b[$1] }END{for(i=1; i<=mx; i++)printf("%s%s",i==1?n:substr(n,index(n,",")+1),i==mx?RS:OFS); for(i=1; i in o; i++)print a[o[i]]}' infile
Country,Network,Details,Amount,Network,Details,Amount,Network,Details,Amount,Network,Details,Amount,Network,Details,Amount
Angola,voda,xxx,10,at&t,xxx,20,mtn,xxx,30
Brazil,voda,yyy,40,voda,yyy,50,at&t,yyy,60,mtn,yyy,70,voda,yyy,80
Zambia,tcl,zzz,90
Run Code Online (Sandbox Code Playgroud)

修改后的代码:

awk 'BEGIN{
            FS=OFS=","
     }
     FNR==1{
            n=$0;
            next
     }
     {
           # this line modified
           # look for char pos of comma, 

           a[$1]=($1 in a ? a[$1] OFS substr($0,index($0,",")+1) : $0);

           if(!($1 in b)){ o[++i]=$1 }; 

           b[$1]++; 
           mx=mx>b[$1]?mx:b[$1] 
     }
    END{
           for(i=1; i<=mx; i++)
              # this line modified
              printf("%s%s",i==1?n:substr(n,index(n,",")+1),i==mx?RS:OFS);

            for(i=1; i in o; i++)
                print a[o[i]]
     }' infile
Run Code Online (Sandbox Code Playgroud)

修改相关说明:

  • index(in, find)

在字符串 in 中搜索字符串 find 的第一次出现,并返回该字符串在字符串 in 中开始出现的字符位置。

  • substr(string, start [, length ])

    返回 string 的一个长度字符长的子字符串,从字符号 start 开始。