我怎样才能删除Unix中的文件中的重复行?

有没有办法在Unix中删除文件中的重复行?

我可以用sort -uuniq命令来完成。 但我想用sedawk 。 那可能吗?

 awk '!seen[$0]++' file.txt 

seen是一个Awk会传递文件的每一行的关联数组。 如果一行不在数组中,则seen[$0]将计算为false。 那! 是一个逻辑NOT运算符,将会将false转换为真。 Awk将打印expression式计算结果为真的行。 seen ++增量,以便在第一次find一行后seen[$0] == 1 ,然后seen[$0] == 2 ,依此类推。
Awk评估一切,但0"" (空string)为true。 如果一个重复的行被放在seen那么!seen[$0]将计算为false,并且该行不会被写入输出。

http://sed.sourceforge.net/sed1line.txt :(请不要问我这是如何工作;-))

  # delete duplicate, consecutive lines from a file (emulates "uniq"). # First line in a set of duplicate lines is kept, rest are deleted. sed '$!N; /^\(.*\)\n\1$/!P; D' # delete duplicate, nonconsecutive lines from a file. Beware not to # overflow the buffer size of the hold space, or else use GNU sed. sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P' 

Perl单线程类似于@ jonas的awk解决scheme:

 perl -ne 'print if ! $x{$_}++' file 

比较之前,此变体将删除尾随的空格:

 perl -lne 's/\s*$//; print if ! $x{$_}++' file 

这个变化在原地编辑文件:

 perl -i -ne 'print if ! $x{$_}++' file 

这种变化就地编辑文件,并做一个备份file.bak

 perl -i.bak -ne 'print if ! $x{$_}++' file 

安德烈·米勒(Andre Miller)在上面发表的一行内容,除了最近版本的sed,当input文件以空白行结束并且没有字符时。 在我的Mac上,我的CPU只是旋转。

无限循环,如果最后一行是空白的,没有字符

sed '$!N; /^\(.*\)\n\1$/!P; D'

不挂,但你失去了最后一行

sed '$d;N; /^\(.*\)\n\1$/!P; D'

解释是在sed常见问题的最后 :

GNU sed的维护者觉得尽pipe有可移植性的问题
这将导致,改变N命令打印(而不是
删除)模式空间更符合自己的直觉
关于“追加下一行”的命令应该如何performance。
另一个有利于改变的事实是“{N; command;}”
如果文件有奇数行,删除最后一行,但是
如果文件具有偶数行,则打印最后一行。

转换使用N的前一个行为的脚本(删除
在达到EOF时的模式空间)到兼容的脚本
所有版本的sed, 改变一个孤独的“N” 到“$ d; N”

使用Vim(Vi兼容)的另一种方法

从文件中删除重复的连续行:

vim -esu NONE +'g/\v^(.*)\n\1$/d' +wq

从文件中删除重复,非连续和非空行:

vim -esu NONE +'g/\v^(.+)$\_.{-}^\1$/d' +wq

第一个解决scheme也来自http://sed.sourceforge.net/sed1line.txt

 $ echo -e '1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5' |sed -nr '$!N;/^(.*)\n\1$/!P;D' 1 2 3 4 5 

核心思想是:

 print ONLY once of each duplicate consecutive lines at its LAST appearance and use D command to implement LOOP. 

解释:

  1. $!N; :如果当前行不是最后一行,则使用N命令将下一行读入pattern space
  2. /^(.*)\n\1$/!P :如果当前pattern space的内容是由\n分隔的两个duplicate string ,这意味着下一行与当前行same ,我们不能根据我们的核心理念 否则,这意味着当前行是所有重复连续行的最后一行,现在我们可以使用P命令在当前pattern space util \n\n也打印)中打印字符。
  3. D :我们使用D命令删除当前pattern space的字符util \n\n也删除),那么pattern space的内容就是下一行。
  4. D命令将强制sed跳转到它的FIRST命令$!N ,但是不会从文件或标准inputstream中读取下一行。

第二个解决scheme很容易理解(从我自己):

 $ echo -e '1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5' |sed -nr 'p;:loop;$!N;s/^(.*)\n\1$/\1/;tloop;D' 1 2 3 4 5 

核心思想是:

 print ONLY once of each duplicate consecutive lines at its FIRST appearance and use : command & t command to implement LOOP. 

解释:

  1. 从inputstream或文件中读取一行并打印一次。
  2. 使用:loop命令设置一个名为looplabel
  3. 使用N读取下一行到pattern space
  4. 如果下一行与当前行相同,使用s/^(.*)\n\1$/\1/删除当前行,我们使用s命令来执行delete操作。
  5. 如果s命令执行成功,则使用tloop命令强制sed跳转到名为looplabel ,这将对下一行执行相同的循环util没有latest printed的行的重复连续行; 否则使用D命令delete与最后一行相同的latest-printed line ,强制sed跳转到第一个命令,即p命令,当前pattern space的内容是下一个新行。
 cat filename | sort | uniq -c | awk -F" " '$1<2 {print $2}' 

使用awk删除重复的行。