在unix中删除完全相同的重复列

时间:2015-01-27 02:49:34

标签: sorting unix awk

假设我有一个文件如下:

number 2 6 7 10 number 6 13  
name1 A B C D name1 B E   
name2 A B C D name2 B E  
name3 B A D A name3 A F  
name4 B A D A name4 A F  

我希望删除完全相同的重复列,输出文件如下:

number 2 6 7 10 13  
name1 A B C D E   
name2 A B C D E  
name3 B A D A F  
name4 B A D A F  

我对行使用sortuniq命令,但从不知道如何处理列。有人能提出一个好方法吗?

4 个答案:

答案 0 :(得分:3)

这是一种使用awk保存订单的方法

awk 'NR==1{for(i=1;i<=NF;i++)b[$i]++&&a[i]}{for(i in a)$i="";gsub(" +"," ")}1' file

输出

number 2 6 7 10 13  
name1 A B C D E   
name2 A B C D E  
name3 B A D A F  
name4 B A D A F  

如何运作

NR==1

如果是第一条记录

for(i=1;i<=NF;i++)

字段上的循环,NF是字段数

b[$i]++&&a[i]

如果$i出现多次(字段i中包含的数据),则使用i的键将元素添加到数组a。

对所有记录(包括记录1)执行下一个块。

{for(i in a)$i="";

对于集合中的每个键,相应的字段为空。

gsub(" +"," ")

删除多余的空格

1

始终评估为true,以便打印所有记录。

答案 1 :(得分:2)

这个Perl单线程将解决这个问题:

perl -an -e '@cols = grep { !$seen{$F[$_]}++ } 0..$#F unless @cols; print join " ", @F[@cols],"\n"' inputfile

-ainputfile的每一行拆分为@F。该文件的第一行用于从左到右构造列索引列表,仅保留那些看不见的列。接下来,它打印@F的切片,其中只包含每行的那些列。

答案 2 :(得分:1)

您可以使用awk:

NR == 1 {
  for (ii = 1; ii <= NF; ii++) {
    cols[$ii] = ii
  }
  for (ii in cols) {
    printf "%s ", ii
  }
  print ""
}

NR > 1 {
  for (ii in cols) {
    printf "%s ", $cols[ii]
  }
  print ""
}

以上内容可能会对列进行重新排序,但如果需要,可以采取更多措施来解决问题。

答案 3 :(得分:1)

删除重复行只能在一个awk命令中完成:

awk '!a[$0]++'

这可以追踪线条出现的次数。一旦出现一行,a[this row]等于1,所以当它再次出现时a[this row]已经为真且!否定了该条件,因此它不会打印出来。

在您的情况下,您要删除重复的列。但是如何创建一个函数transpose来将行转换为列,反之亦然?

我已经在Using bash to sort data horizontally的回答中做到了:

transpose () {
  awk '{for (i=1; i<=NF; i++) a[i,NR]=$i; max=(max<NF?NF:max)}
        END {for (i=1; i<=max; i++)
              {for (j=1; j<=NR; j++) 
                  printf "%s%s", a[i,j], (j<NR?OFS:ORS)
              }
        }'
}

然后,它变得微不足道了:

$ cat file | transpose | awk '!a[$0]++' | transpose
number 2 6 7 10 13
name1 A B C D E
name2 A B C D E
name3 B A D A F
name4 B A D A F