awk - 不同值的表

时间:2011-12-26 06:03:45

标签: linux bash shell unix scripting

用这个“|”分隔文件:dummy.dat

sid|storeNo|latitude|longitude
2|1|-28.03720000
9|2
10
jgn352|1|-28.03720000
9|2|fdjkjhn422-405
0000543210|gfdjk39

例如,纬度字段中的值“-28.03720000”出现两次,然后在输出中它将出现一次但在其结尾处(2)。另一个例子,值“2”在sid字段中出现一次但在storeno字段中出现两次 - 因此对于输出,它将在sid字段下面有一个条目(在末尾带有“(1)”)和storeno下面的一个条目字段(末尾有“(2)”)。

期望的结果:

sid|storeNo|latitude|longitude
9(2)|1(2)|-28.03720000(2)
0000543210(1)|2(2)|fdjkjhn422-405(1)
10(1)|gfdjk39(1)    
2(1)
jgn352(1)

可接受的期望结果的另一个例子(给定相同的输入文件):

sid|storeNo|latitude|longitude
9(2)|2(2)|-28.03720000(2)
jgn352(1)|1(2)|fdjkjhn422-405(1)
10(1)|gfdjk39(1)    
0000543210(1)
2(1)

产生上述输出的通用解决方案是什么?我对awk,bash,perl.etc持开放态度 它是每个字段的不同值(具有“()”中该值的出现次数,然后按出现次数排序desc):

找到了这两个代码片段,它们提供了一般性的想法,但只是采用不同的输出格式:

Script 1:
awk -F"|" ' {
                for( i = 1; i <= NF; i++ )
                {
                        count[i " " $(i)]++;    # count by field number and field value
                        uniq[$(i)] = 1;         # save a list of unique strings
                }
                if( NF > fields )
                        fields = NF;            # in case a variable number in file; capture max
        }
        END {
                for( i = 1; i <= fields; i++ )
                {
                        printf( "field %d\n", i );
                        for( x in uniq )
                                if( count[i " " x] )
                                        printf( "%s (%d)\n", x, count[i " " x] );  # print by field and value
                        printf( "\n" );
                }
        } ' dummy.dat

Script 2:
awk -F"|" '{for (i=1;i<=NF;i++) a[i FS $i]++} END {for (i in a) print i,"(",a[i],")" |"sort -n" } ' dummy.dat

1 个答案:

答案 0 :(得分:2)

awk -F'|' '

FNR==NR{
  if(FNR>1)
    for(i=1;i<=NF;i++)
      a[$i,i]++
  next
}
FNR==1{print}
FNR>1{
  for(j=1;j<=NF;j++)
    if(b[$j,j]++)
      printf("|")
    else
      printf("%s(%s)|",$j,a[$j,j])
  print ""
}' ./dummy.dat ./dummy.dat | sed 's/|*$//'

输出

sid|storeNo|latitude|longitude
2(1)|1(2)|-28.03720000(2)
9(2)|2(2)
10(1)
jgn352(1)
||fdjkjhn422-405(1)
0000543210(1)|gfdjk39(1)

注意: 摆脱尾随|将需要额外的工作。希望这就足够了。
我刚刚将最终输出传递给sed 's/|*$//'