假设我有一个文件如下:
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
我对行使用sort
和uniq
命令,但从不知道如何处理列。有人能提出一个好方法吗?
答案 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
-a
将inputfile
的每一行拆分为@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