成对删除重复的行?

Wil*_*ard 16 sed text-processing uniq

我今天遇到了这个用例。乍一看似乎很简单,但是摆弄sort, uniq,sedawk发现它很重要。

如何删除所有成对的重复行?换句话说,如果给定行有偶数个重复项,则将其全部删除;如果重复行数为奇数,则删除除一行之外的所有行。(可以假设已排序的输入。)

一个干净优雅的解决方案是可取的。

示例输入:

a
a
a
b
b
c
c
c
c
d
d
d
d
d
e
Run Code Online (Sandbox Code Playgroud)

示例输出:

a
d
e
Run Code Online (Sandbox Code Playgroud)

Wil*_*ard 6

我在sed发布这个问题后不久就得出了答案;sed到目前为止没有其他人使用过,所以这里是:

sed '$!N;/^\(.*\)\n\1$/d;P;D'
Run Code Online (Sandbox Code Playgroud)

稍微处理一下更普遍的问题(删除三行或四行或五行呢?)提供了以下可扩展的解决方案:

sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp
Run Code Online (Sandbox Code Playgroud)

扩展以删除三重行:

sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp
Run Code Online (Sandbox Code Playgroud)

或者删除四边形线:

sed -e ':top' -e '$!{/\n.*\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1\n\1$/d;P;D' temp
Run Code Online (Sandbox Code Playgroud)

sed 与大多数其他选项相比,还有一个额外的优势,那就是它能够真正在流中操作,不需要比要检查重复的实际行数更多的内存存储。


正如cuonglm 在评论中指出的那样,将语言环境设置为 C 是必要的,以避免无法正确删除包含多字节字符的行。所以上面的命令变成了:

LC_ALL=C sed '$!N;/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp
# Etc.
Run Code Online (Sandbox Code Playgroud)

  • @Wildcard:您可能希望将语言环境设置为 `C`,否则在多字节语言环境中,该语言环境中的无效字符会导致命令失败。 (2认同)