如何在不对Unix进行排序的情况下删除文件中的重复行?

unix shell scripting sed awk

91472 观看

8回复

34097 作者的声誉

有没有一种方法可以删除Unix中文件中的重复行?

我可以使用sort -uuniq命令来实现,但是我想使用sedawk。那可能吗?

作者: Vijay 的来源 发布者: 2009 年 9 月 18 日

回应 (8)


28

11695 作者的声誉

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'
作者: Andre Miller 发布者: 18.09.2009 01:04

253

25217 作者的声誉

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

seen是Awk会将文件的每一行传递到的关联数组。如果行不在数组中,seen[$0]则将评估为false。该!是逻辑NOT运算符和将反转假为真。Awk将打印表达式计算结果为true的行。的++增量seen,以便seen[$0] == 1在第一时间线被发现,在此之后seen[$0] == 2,依此类推。
Awk将除0""(空字符串)以外的所有内容评估为true。如果放置重复的行,seen则结果!seen[$0]将为false,并且该行将不会写入输出。

作者: Jonas Elfström 发布者: 18.09.2009 01:07

7

1040 作者的声誉

上面安德烈·米勒(Andre Miller)发布的单行代码适用,但当输入文件以空行结尾且没有字符时,最新版本的sed除外。在Mac上,我的CPU旋转了。

如果最后一行为空并且没有字符,则为无限循环

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

没有挂起,但是您丢失了最后一行

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

解释位于sed FAQ的最后

GNU sed维护者认为,尽管
这将导致可移植性问题,但更改N命令以打印(而不是
删除)模式空间与人们
对“添加下一行”命令应该如何表现的直觉更加一致。
支持此更改的另一个事实是,
如果文件的行数为奇数,“ {N; command;}”将删除最后一行,而如果文件的行数为偶数,
则将打印最后一行。

要将以前使用N的行为(
到达EOF时删除模式空间)的脚本转换为
与sed所有版本兼容的脚本,请更改一个单独的“ N;”。改为“ $ d; N;”

作者: Bradley Kreider 发布者: 05.11.2010 01:25

4

973 作者的声誉

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

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

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

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

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

作者: Bohr 发布者: 04.09.2013 04:01

-4

152 作者的声誉

cat filename | sort | uniq -c | awk -F" " '$1<2 {print $2}'

使用awk删除重复的行。

作者: Sadhun 发布者: 18.06.2014 06:09

12

1863 作者的声誉

Perl一线式类似于@jonas的awk解决方案:

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
作者: Chris Koknat 发布者: 11.09.2015 12:17

3

802 作者的声誉

第一个解决方案也来自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:如果current的内容pattern space是两个以duplicate string分隔的\n,则表示下一行是same当前行的,我们将无法按照我们的核心思想打印它;否则,这意味着当前行是它所有重复的连续行的最后出现,我们现在可以使用P命令在当前pattern spaceutil中打印字符\n\n也已打印)。
  3. D:我们使用D命令删除当前pattern spaceutil中的字符\n\n也已删除),然后的内容pattern space是下一行。
  4. and D命令将强制sed跳转到其FIRST命令$!N,但不会从文件或标准输入流中读取下一行。

第二种解决方案很容易理解(对我自己而言):

$ 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. 从输入流或文件中读取新行并打印一次。
  2. 使用:loop命令设置一个label命名loop
  3. 用于N将下一行读入pattern space
  4. 使用s/^(.*)\n\1$/\1/删除当前行,如果下一行是同当前行,我们使用s命令来执行delete动作。
  5. 如果s命令执行成功,则使用tloop命令强制sed跳转到labelnamed loop,这将对下一行进行相同的循环,直到该行没有重复的连续行latest printed;否则,使用Dcommand到delete与相同的行latest-printed line,并强制sed跳到第一个命令,即该p命令,当前内容pattern space是下一个新行。
作者: Weike 发布者: 05.06.2017 06:25

-3

4 作者的声誉

可以使用awk做到这一点。Line
在下面显示唯一的值

awk file_name | uniq

您可以将这些唯一值输出到新文件

awk file_name | uniq > uniq_file_name

新文件uniq_file_name将仅包含唯一值,没有重复项

作者: Aashutosh 发布者: 14.08.2018 09:24
32x32