使用 shell 删除列中的重复字符串

D.P*_*ker 11 shell awk sed

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

OG0000000   PF03169,PF03169,PF03169,MAC1_004431-T1,
OG0000002   PF07690,PF00083,PF00083,PF07690,PF00083,
OG0000003   MAC1_000127-T1,
OG0000004   PF13246,PF00689,PF00690,
OG0000005   PF00012,PF01061,PF12697,PF00012,
Run Code Online (Sandbox Code Playgroud)

我只想删除第二列中的重复字符串,而不更改第一列中的任何内容,以便我的最终输出如下所示:

OG0000000   PF03169,MAC1_004431-T1,
OG0000002   PF07690,PF00083,
OG0000003   MAC1_000127-T1,
OG0000004   PF13246,PF00689,PF00690,
OG0000005   PF00012,PF01061,PF12697,
Run Code Online (Sandbox Code Playgroud)

我尝试使用 awk 来启动它。

awk 'BEGIN{RS=ORS=","} !seen[$0]++' file.txt
Run Code Online (Sandbox Code Playgroud)

但我的输出看起来像这样,如果重复的字符串首先出现,则仍然存在一些重复项。

OG0000000   PF03169,PF03169,MAC1_004431-T1,
OG0000002   PF07690,PF00083,PF07690,
OG0000003   MAC1_000127-T1,
OG0000004   PF13246,PF00689,PF00690,
OG0000005   PF00012,PF01061,PF12697,PF00012,
Run Code Online (Sandbox Code Playgroud)

我意识到问题是因为 awk 抓取的第一行是第一个逗号之前的所有内容,但我对 awk 命令仍然很粗糙,无法弄清楚如何在不弄乱第一列的情况下解决这个问题。提前致谢!

anu*_*ava 11

awk应该适合你:

awk -F '[\t,]' '
{
   printf "%s", $1 "\t"
   for (i=2; i<=NF; ++i) {
      if (!seen[$i]++)
         printf "%s,", $i
   }
   print ""
   delete seen
}' file

OG0000000   PF03169,MAC1_004431-T1,
OG0000002   PF07690,PF00083,
OG0000003   MAC1_000127-T1,
OG0000004   PF13246,PF00689,PF00690,
OG0000005   PF00012,PF01061,PF12697,
Run Code Online (Sandbox Code Playgroud)

PS:根据显示的预期输出,此解决方案还在每行中显示一个尾随逗号。

  • 您不能依赖通常的 `(i&lt;NF ? "," : ORS)` 习惯用法,因为如果 $NF 是重复的,那么您将不会打印该行的 ORS。 (2认同)

Dav*_*ica 8

另一种方法是使用相同的数组$2,并为发布的非重复值的位置保留一个单独的计数器,如下所示:

awk '
  { 
    printf "%s\t", $1
    delete seen
    n = split($2,arr,",")
    pos = 0
    for (i=1;i<=n;i++) { 
      if (! (arr[i] in seen)) { 
        printf "%s%s", pos ? "," : "", arr[i]
        seen[arr[i]]=1
        pos++ 
      }
    }
    print ""
  }
' file.txt
Run Code Online (Sandbox Code Playgroud)

示例输出

根据您的输入file.txt,输出为:

OG0000000       PF03169,MAC1_004431-T1,
OG0000002       PF07690,PF00083,
OG0000003       MAC1_000127-T1,
OG0000004       PF13246,PF00689,PF00690,
OG0000005       PF00012,PF01061,PF12697,
Run Code Online (Sandbox Code Playgroud)


Rav*_*h13 6

根据您显示的示例和尝试,请尝试以下awk代码。我们不需要设置RSORS它们分别是记录分隔符和输出记录分隔符,在这个需求中我们不需要设置。将 FS 和 OFS 设置为,相应的打印字段。

awk '
BEGIN{ FS=","; OFS="\t" }
{
  val=""
  delete arr
  num=split($2,arr,",")
  for(i=1;i<=num;i++){
   if(!arr[$i]++){
      val=(val?val ",":"") $i
   }
  }
  print $1,val
}
' Input_file
Run Code Online (Sandbox Code Playgroud)

  • 等一下 - 当 `$2` 已经是 `FS` 分割的结果时,你不能用 `FS` 分割 `$2` (当 `FS` 是 `,` 时,用 `,` 分割也是如此) (2认同)

pot*_*ong 6

这可能对你有用(GNU sed):

sed -E ':a;s/(\s+.*(\b\S+,).*)\2/\1/;ta' file
Run Code Online (Sandbox Code Playgroud)

遍历一行,删除空格后的所有重复字符串。


Hat*_*ess 5

使用GNUsed

$ sed -E ':a;s/([^ \t]*[ \t]+)?(([[:alnum:]]+,).*)\3/\1\2/;ta' input_file
OG0000000   PF03169,MAC1_004431-T1,
OG0000002   PF07690,PF00083,
OG0000003   MAC1_000127-T1,
OG0000004   PF13246,PF00689,PF00690,
OG0000005   PF00012,PF01061,PF12697,
Run Code Online (Sandbox Code Playgroud)