如何连接基于一条共同线的线?

How to concatenate lines based on one line in common?

我有一个制表符分隔的文件,如下所示:

4S2P_1:A    4S2P_1:A
4S2P_1:A    6PXX_1:A
4S2P_1:A    6HB8_1:A
4S2P_1:A    6HOO_1:A
4S2P_1:A    6I5D_1:A
4S2R_1:A    4S2R_1:A
4S2C_1:A    4S2C_1:A
4S2C_1:A    4S2B_1:A
4S2E_1:A    4S2E_1:A
4S2E_1:A    5XB5_1:A
4S2E_1:A    5XBH_1:A

创建文件后,第二列中的序列与第一列中的序列相似。 4S2P_1:A本身与6Q5B_1:A、6PXX_1:A、6HB8_1:A等类似。 4S2R_1:A 只是和自己相似。

我想将文件解析为如下所示:

4S2P_1:A 6PXX_1:A 6HB8_1:A 6HOO_1:A 6I5D_1:A
4S2E_1:A 5XB5_1:A 5XBH_1:A
4S2C_1:A 4S2B_1:A
4S2R_1:A

所以我希望输出的第一列和链接到它的列在一行中用 space 分隔,并使形成的簇按降序排列。

我想用 awk 来做这个。

我试过用这个:

awk -F '\t' '{print *" "}' 

但它给了我这个输出:

04S2P_1:A
05DTT_1:A
07ASS_1:A
07AUX_1:A
05HAQ_1:A
05HAP_1:A
05HAR_1:A

开头加0,相似序列不在同一行

通常使用散列来使列表唯一。

#! /bin/bash

declare -A hash

while read -r c1 c2; do
  hash[$c1]+=$'\t'"$c2"
done

for key in "${!hash[@]}"; do
  printf '%s%s\n' "$key" "${hash[$key]}"
done

缺点是,您失去了原来的排序顺序。但在我看来,你并不关心原来的顺序。如果您想按每行的长度对输出进行排序,您可以选择 question.

的答案之一

这是一个简单的 Awk 脚本,用于将具有相同键的值提升到同一行。

awk ' != prev { if(prev) printf "\n";
     prev=; printf "%s", ; next }
   { printf " %s",  }
  END { if (prev) printf "\n" }' file

要按每条记录的长度排序,你需要在阅读时记住一些东西。上面的代码因其简单性和健壮性(应该适用于任何大小的文件)而很有吸引力,但我们可以让它更复杂一点,在每行前面打印一个排序键,代价是需要将每条完整记录保存在记忆,直到我们知道它的长度。

awk 'function pr () { printf "%i\t", n; printf "%s", a[1];
    for(i=2; i<=n; ++i) printf " %s", a[i];
    printf "\n"; delete a; n=0 }
   != prev { if (prev) pr(); prev=; a[1]=; n=1; next }
  { a[++n] =  }
  END { if (n) pr() }' file |
sort -t $'\t' -k1rn |
cut -f2-