Wil*_*ard 16 sed text-processing uniq
我今天遇到了这个用例。乍一看似乎很简单,但是摆弄sort, uniq,sed并awk发现它很重要。
如何删除所有成对的重复行?换句话说,如果给定行有偶数个重复项,则将其全部删除;如果重复行数为奇数,则删除除一行之外的所有行。(可以假设已排序的输入。)
一个干净优雅的解决方案是可取的。
示例输入:
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)
我在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)