sed/awk:删除第一次出现后的类似行

sed/awk:删除第一次出现后的类似行

我有:

constant1apple_____constant2asdfkjo___constant3
constant1apple_____constant2fdlkjef___constant3
constant1watermelonconstant2sdlfkeio__constant3
constant1banana____constant2asdfoie___constant3
constant1apple_____constant2soeivmn___constant3
constant1orange____constant2vjflkdslj_constant3
constant1watermelonconstant2xcvlvdiosnconstant3
constant1orange____constant2wieonvow__constant3
constant1apple_____constant2woemnivoiwconstant3

我只想保留第一次出现水果名称的行

输出应该是这样的:

constant1apple_____constant2asdfkjo___constant3
constant1watermelonconstant2sdlfkeio__constant3
constant1banana____constant2asdfoie___constant3
constant1orange____constant2vjflkdslj_constant3

重要笔记:

  • 水果名称可以是任何我不知道的名字,但它们的长度都相同

  • 水果名称后面的随机字符串可以是任意内容,但也要具有特定的长度

不知道该怎么做

答案1

使用 awk(或 perl,或大多数具有关联数组的其他语言)来做到这一点会更容易一些:

awk '!seen[substr($0, 10, 10)]++' input.txt

awk '{ fruit = substr($0, 10, 10); if (!seen[fruit]++) print }' input.txt

(awk 脚本的结构如下:match1 {code1} match2 {code2} ...第一个变体仅指定匹配条件但不指定代码,使用隐式默认值{print;};第二个变体执行相反的操作但实现相同的目的。无论哪种方式,都更容易使用。)

seen是一个关联数组(一个字典/哈希表),用于计算第二个字段到目前为止被看到的次数。对于每一行,seen[x]++增加保存的值seen[x]并同时返回上一个值。如果上一个值为 0,则表示水果第一次被看到。

在这个版本中,substr(input, start, count)用于从 $0(代表整行)中提取 10 个字符,从第 10 个字符开始。(在之前的版本中,数组键是$2第二个以空格分隔的列。)


awk 运行良好,但取决于您计划进行多少过滤(如果不仅仅是提取唯一的第二列),最好从更通用的语言开始:

#!/usr/bin/env python3
import sys
seen = set()
for line in sys.stdin:
    fruit = line[9:19]
    if fruit not in seen:
        seen.add(fruit)
        sys.stdout.write(line)

或者,如果可以安全地重新排序名称,则可以使用uniq它们来重复数据删除:

cat input.txt | sort | uniq --skip-chars=9 --check-chars=10

如果你只需要水果名称本身,而忽略其余部分,你可以通过提取列来实现第一的并使用uniq剩下的:

cat input.txt | cut -c 10-19 | sort | uniq

cat input.txt | sed -r 's/^.{9}(.{10}).*/\1/' | sort | uniq

相关内容