![是否可以使用正则表达式删除列表中的特定重复字符?](https://linux22.com/image/197875/%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%88%A0%E9%99%A4%E5%88%97%E8%A1%A8%E4%B8%AD%E7%9A%84%E7%89%B9%E5%AE%9A%E9%87%8D%E5%A4%8D%E5%AD%97%E7%AC%A6%EF%BC%9F.png)
我有一个列的列表,其中包含约 100 行,其中一些行是重复的,我的目的是摆脱具体的重复行并仅保留一复制,而其他行保持不变。
我正在处理的文件的摘录:
V(Mn9)
V(C1,H3)
V(Mn6)
V(Mn6)
V(C4,H6)
V(Mn9)
V(Mn9)
V(C1,Mn6)
V(C4,Mn9)
V(Mn6)
V(C1,C4)
C(Mn9)
C(Mn6)
C(C1)
C(C4)
C(Mn9)
C(Mn6)
V(C1,H2)
V(Mn9)
V(Mn6)
V(C4,H5)
我的目的是删除所有包含 C(Xx0-9) 的重复行并保留其中之一并保留 V(Xxx..)。
我寻求的结果:
V(Mn9)
V(C1,H3)
V(Mn6)
V(Mn6)
V(C4,H6)
V(Mn9)
V(Mn9)
V(C1,Mn6)
V(C4,Mn9)
V(Mn6)
V(C1,C4)
C(C1)
C(C4)
C(Mn9)
C(Mn6)
V(C1,H2)
V(Mn9)
V(Mn6)
V(C4,H5)
我使用了命令:
sed '0,/C(Mn9)/{/C(Mn9)/d}' inputfile.txt | sed '0,/C(Mn6)/{/C(Mn6)/d}'
它正在工作,但对于整个文件来说还不够好,因为有很多 C(Xx1-50),我想使用正则表达式,但我不知道如何,这就是为什么我需要你的帮助。
答案1
$ awk '!(/^C\(..[0-9])$/ && seen[$0]++)' file
V(Mn9)
V(C1,H3)
V(Mn6)
V(Mn6)
V(C4,H6)
V(Mn9)
V(Mn9)
V(C1,Mn6)
V(C4,Mn9)
V(Mn6)
V(C1,C4)
C(Mn9)
C(Mn6)
C(C1)
C(C4)
V(C1,H2)
V(Mn9)
V(Mn6)
V(C4,H5)
上面假设示例输入中的可见字符之前/之后没有空格。如果这样做,则删除它们,例如:
$ awk '{gsub(/^[[:space:]]+|[[:space:]]+$/,"")} !(/^C\(..[0-9])$/ && seen[$0]++)' file
V(Mn9)
V(C1,H3)
V(Mn6)
V(Mn6)
V(C4,H6)
V(Mn9)
V(Mn9)
V(C1,Mn6)
V(C4,Mn9)
V(Mn6)
V(C1,C4)
C(Mn9)
C(Mn6)
C(C1)
C(C4)
V(C1,H2)
V(Mn9)
V(Mn6)
V(C4,H5)
答案2
我建议使用sed
收集保留空间中的行来检查它们之前是否出现过:
sed -n 'H;G;/^\(C([^)]*)\).*\1 *\n/!P'
H
将当前行追加到保留空间G
将保留空间与我们见过的所有行附加到模式空间C([^)]*)
是这些模式之一C(…)
,^
将其锚定到行的开头,并且它被 包围\(…\)
,因此可以\1
稍后反向引用。我们需要\1 *\n
作为模式,带有换行符(在可能的空格之后)以避免匹配末尾新添加的行。因此整个模式/^\(C([^)]*)\).*\1 *\n/
与具有重复项的行匹配C(…)
,因此仅当这!
不匹配时,P
-n
在第一个换行符之前打印所有内容(= 没有附加的保留空间),而默认输出被该选项抑制
请注意,根据您的sed
版本和文件大小,这可能会失败,因为随着时间的推移,所有行都将存储在内存中。