根据两列(双向)删除重复的行,仅保留一个

时间:2019-12-10 08:08:29

标签: linux awk

我想从制表符分隔的文件中删除重复的行,如下所示:

 arahy.Tifrunner.gnm1.ann1.A4HWYP   arahy.Tifrunner.gnm1.ann1.BWH72M
 arahy.Tifrunner.gnm1.ann1.A4HWYP   arahy.Tifrunner.gnm1.ann1.PK5V4W
 arahy.Tifrunner.gnm1.ann1.BWH72M   arahy.Tifrunner.gnm1.ann1.A4HWYP
 arahy.Tifrunner.gnm1.ann1.D7QF3J   arahy.Tifrunner.gnm1.ann1.A6ZB5M
 arahy.Tifrunner.gnm1.ann1.A6ZB5M   arahy.Tifrunner.gnm1.ann1.D7QF3J

基于第1列和第2列获取具有一个方向行的输出文件,如下所示:

 arahy.Tifrunner.gnm1.ann1.A4HWYP   arahy.Tifrunner.gnm1.ann1.BWH72M
 arahy.Tifrunner.gnm1.ann1.A4HWYP   arahy.Tifrunner.gnm1.ann1.PK5V4W
 arahy.Tifrunner.gnm1.ann1.D7QF3J   arahy.Tifrunner.gnm1.ann1.A6ZB5M

我正在尝试代码

awk -F'\t' '!x[$2];{x[$1]++}' input.txt > out.txt

但是它没有提供所需的输出,而是仅仅删除了原始文件的最后一行。 有什么办法可以使用awk和/或sort?

3 个答案:

答案 0 :(得分:4)

$ awk 'BEGIN{FS=OFS="\t"}
       !(($1 FS $2 in x) || ($2 FS $1 in x));
       {x[$1 FS $2]}' ip.txt
arahy.Tifrunner.gnm1.ann1.A4HWYP    arahy.Tifrunner.gnm1.ann1.BWH72M
arahy.Tifrunner.gnm1.ann1.A4HWYP    arahy.Tifrunner.gnm1.ann1.PK5V4W
arahy.Tifrunner.gnm1.ann1.D7QF3J    arahy.Tifrunner.gnm1.ann1.A6ZB5M
  • BEGIN{FS=OFS="\t"}将输入和输出字段分隔符设置为制表符
  • {x[$1 FS $2]}使用由制表符分隔的第一和第二字段作为键
  • $1 FS $2 in x$2 FS $1 in x检查第一和第二字段是否以任何顺序作为键存在

您还可以将其简化为:

awk 'BEGIN{FS=OFS="\t"} !(($0 in x) || ($2 FS $1 in x)); {x[$0]}'

或(只是意识到不需要OFS)

awk -F'\t' '!(($0 in x) || ($2 FS $1 in x)); {x[$0]}'

答案 1 :(得分:2)

另一个awk:

$ awk '!a[($1<$2?$1:$2),($1<$2?$2:$1)]++' file

输出:

arahy.Tifrunner.gnm1.ann1.A4HWYP        arahy.Tifrunner.gnm1.ann1.BWH72M
arahy.Tifrunner.gnm1.ann1.A4HWYP        arahy.Tifrunner.gnm1.ann1.PK5V4W
arahy.Tifrunner.gnm1.ann1.D7QF3J        arahy.Tifrunner.gnm1.ann1.A6ZB5M

如果列中有空格,则应使用awk -F"\t"¸

答案 2 :(得分:0)

我不是awk专家,因此,如果您有兴趣,可以使用Bash解决方案:

declare -A db
while read line; do
  index="$(sed 's,[[:space:]]\+,\n,g' <<<"$line" | sort)"
  [ -z "${db[$index]}" ] && echo "$line"
  db[$index]=1
done < input.txt > out.txt

这里的窍门是创建一个不关心记录中值顺序的索引,我可以通过使用sed将每个记录转换为一组行,然后运行它来完成此操作。 sort。理想情况下,sort允许我们对“单词”进行排序,但AFAIK不允许。