仅打印第一列中仅包含一个值副本的行

仅打印第一列中仅包含一个值副本的行

我有一堆文件,每个文件看起来都是这样的:

HWI-ST913:300:C5W5DACXX:7:1101:1477:2147    Ha1_00044161    80.6    31  6   0   94  2   1   31  5.1e-11 63.2
HWI-ST913:300:C5W5DACXX:7:1101:1629:2128    Ha6_00047653    90.9    33  3   0   2   100 173 205 5.1e-11 63.2
HWI-ST913:300:C5W5DACXX:7:1101:1649:2180    Ha9_00011743    100.0   33  0   0   100 2   274 306 7.8e-12 65.9
HWI-ST913:300:C5W5DACXX:7:1101:1649:2180    Ha5_00006578    100.0   33  0   0   100 2   98  130 7.8e-12 65.9
HWI-ST913:300:C5W5DACXX:7:1101:1649:2180    Ha12_00033467   100.0   33  0   0   100 2   91  123 7.8e-12 65.9
HWI-ST913:300:C5W5DACXX:7:1101:6099:2062    B2KZF9_PICAB    100.0   33  0   0   1   99  73  105 2.4e-13 70.9
HWI-ST913:300:C5W5DACXX:7:1101:6891:2170    Ha2_00026275    87.9    33  4   0   2   100 27  59  9.3e-13 68.9
HWI-ST913:300:C5W5DACXX:7:1101:6891:2170    Ha13_00015465   87.9    33  4   0   2   100 884 916 9.3e-13 68.9
HWI-ST913:300:C5W5DACXX:7:1101:6891:2170    Ha17_00009154   87.9    33  4   0   2   100 420 452 9.3e-13 68.9

我只想保留第一列唯一的那些行。这是我想要的输出:

HWI-ST913:300:C5W5DACXX:7:1101:1477:2147    Ha1_00044161    80.6    31  6   0   94  2   1   31  5.1e-11 63.2
HWI-ST913:300:C5W5DACXX:7:1101:1629:2128    Ha6_00047653    90.9    33  3   0   2   100 173 205 5.1e-11 63.2
HWI-ST913:300:C5W5DACXX:7:1101:6099:2062    B2KZF9_PICAB    100.0   33  0   0   1   99  73  105 2.4e-13 70.9

答案1

KISS 方法awk:维护一个行数组和一个计数 - 然后仅打印末尾计数为 1 的行:

awk '{a[$1]=$0; c[$1]++} END{for (i in a) {if (c[i] == 1) print a[i]}}' file

uniq或者,如果您有支持-w( ) 选项的版本--check-chars并且:

  1. 您的数据按第一个字段排序;并且

  2. 第一个字段的宽度是恒定的

那么你可以用它来代替:

uniq -uw 40 file
HWI-ST913:300:C5W5DACXX:7:1101:1477:2147    Ha1_00044161    80.6    31  6   0   94  2   1   31  5.1e-11 63.2
HWI-ST913:300:C5W5DACXX:7:1101:1629:2128    Ha6_00047653    90.9    33  3   0   2   100 173 205 5.1e-11 63.2
HWI-ST913:300:C5W5DACXX:7:1101:6099:2062    B2KZF9_PICAB    100.0   33  0   0   1   99  73  105 2.4e-13 70.9

这样做的优点是保留原始文件的顺序 - 如果这对您的应用程序很重要。

答案2

一种方法可能就是这样。需要对同一文件进行双重解析,但结果按顺序打印:

$ awk 'NR==FNR{f1[$1]++;next}f1[$1]==1' file1 file1
HWI-ST913:300:C5W5DACXX:7:1101:1477:2147    Ha1_00044161    80.6    31  6   0   94  2   1   31  5.1e-11 63.2
HWI-ST913:300:C5W5DACXX:7:1101:1629:2128    Ha6_00047653    90.9    33  3   0   2   100 173 205 5.1e-11 63.2
HWI-ST913:300:C5W5DACXX:7:1101:6099:2062    B2KZF9_PICAB    100.0   33  0   0   1   99  73  105 2.4e-13 70.9

答案3

仅考虑输入文件已排序,以下内容将适用于任何符合 POSIX 的系统:

sed 's/ .*//' file.txt | uniq -u | join - file.txt

如果原始文档中的空格分隔符实际上是制表符,则可以将sed调用替换为cut -f1 file.txt,并使其余部分保持不变。

答案4

仅扫描一次文件按照与输入文件相同的顺序打印 uniq 行,使用:

在 GNU awk 中(使用“sorted_in”来确保数组的有序扫描):使用三个数组:

  1. 1 用于计算重复行数 (c[]),
  2. 一个用于行的排序顺序 (s[]) 和
  3. 一个用于它们自身的行 (v[])

最后,只打印计数为 1 的行。

awk 'BEGIN { PROCINFO["sorted_in"] = "@ind_num_asc" ; i=0}
        !c[$1]++{s[++i]=$1;v[i]=$0}
     END{for(i in v){if(c[s[i]]==1){print v[i]}}}' infile

请注意,将!c[$1]++仅捕获第一个字段的第一次出现

相关内容