删除重复的行,同时保持行的顺序

som*_*533 20 sed awk perl text-processing

[root@server]# awk '!seen[$0]++' out.txt > cleaned
awk: (FILENAME=out.txt FNR=8547098) fatal error: internal error
Aborted
[root@server]#
Run Code Online (Sandbox Code Playgroud)

“服务器”具有:8 GByte RAM + 16 GByte SWAP,x>300 GByte 可用空间,amd64,桌面 CPU。科学 Linux 6.6。没有其他东西在它上面运行来制作 LOAD。Awk 在几秒钟后中止.. out.txt 是 ~1.6 GByte。GNU awk 3.1.7。

问题:如何在保持行的顺序的同时删除重复的行?大小写也很重要,例如:“A”和“a”是两条不同的行,必须保留。但是“a”和“a”是重复的,只需要第一个。

答案可能是任何东西.. 如果 awk 对此不利.. 那么 perl/sed.. 问题是什么?

[root@server]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 61945
max locked memory       (kbytes, -l) 99999999
max memory size         (kbytes, -m) unlimited
open files                      (-n) 999999
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 99999999
cpu time               (seconds, -t) unlimited
max user processes              (-u) 61945
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[root@server]# 
Run Code Online (Sandbox Code Playgroud)

更新:我在 RHEL 机器上试过这个,它没有中止,但我没有时间等待它完成..为什么 SL linux 与 RHEL 不同?

更新:我正在尝试使用 Ubuntu 14 虚拟主机.. 到目前为止它有效!这不是 ulimit 问题:mawk 1.3.3

root@asdf-VirtualBox:~# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 51331
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 51331
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
root@asdf-VirtualBox:~# 
Run Code Online (Sandbox Code Playgroud)

ter*_*don 31

我怀疑它会有所作为,但以防万一,这里是如何在 Perl 中做同样的事情:

perl -ne 'print if ++$k{$_}==1' out.txt
Run Code Online (Sandbox Code Playgroud)

如果问题是将唯一行保留在内存中,则将遇到与awk您尝试过的相同的问题。因此,另一种方法可能是:

cat -n out.txt | sort -k2 -k1n  | uniq -f1 | sort -nk1,1 | cut -f2-
Run Code Online (Sandbox Code Playgroud)

这个怎么运作:

  1. 在 GNU 系统上,cat -n将在每行前面加上一定数量的空格和<tab>字符后的行号。cat将此输入表示通过管道传输到sort.

  2. sort的-k2选项指示它在排序时只考虑从第二个字段到行尾的字符sort,默认情况下在空格(或cat插入的空格和<tab>)上拆分字段。
    后跟 时-k1n,首先sort考虑第二个字段,然后再-k2考虑(在相同字段的情况下)考虑第一个字段,但按数字排序。因此,重复的行将按它们出现的顺序排列在一起。

  3. 结果通过管道传送到uniq- 被告知忽略第一个字段(-f1- 并且也由空格分隔) - 这会导致原始文件中的唯一行列表并通过管道返回到sort.
  4. 这次sort以数字方式对第一个字段(cat插入的行号)进行排序,将排序顺序恢复为原始文件中的排序顺序并将这些结果通过管道传输到cut.
  5. 最后,cut删除由 插入的行号cat。这是通过cut仅从第二个字段打印到行尾来实现的(并且cut的默认分隔符是<tab>字符)。

为了显示:

$ cat file
bb
aa
bb
dd
cc
dd
aa
bb
cc
$ cat -n file | sort -k2 | uniq -f1 | sort -k1 | cut -f2-
bb
aa    
dd
cc
Run Code Online (Sandbox Code Playgroud)

  • “排序”的好解决方案!但大多数“sort”本身都可以执行“uniq”,因此您可以通过“sort -uk2 |”来缩短脚本的长度。排序-bk1,1n` (2认同)

JJo*_*oao 7

#!/usr/bin/perl 
use DB_File;
tie %h, 'DB_File';

while(<>){ not $h{$_} and print and $h{$_}=1 }
Run Code Online (Sandbox Code Playgroud)

编辑 1:它真的有效吗?(比较)

Sol1 : Terdon et all Schwartzian-transform-like one-liner
    cat -n _1 | sort -uk2 | sort -nk1 | cut -f2-

Sol2 : perl  + DB_File (this answer)
    perl dbfile-uniq _1

Sol3 : PO (John W. Gill solution has a similar behavior)
    awk '!seen[$0]++' _1

Sol4: Terdon perl
    perl -ne 'print if ++$k{$_}==1' _1
Run Code Online (Sandbox Code Playgroud)

案例1:100_000_000 个随机数(每个 5 位),566Mbytes,31_212 个不同的值:

$ while true ; do echo $RANDOM; done | head -100000000 > _1
Run Code Online (Sandbox Code Playgroud)

案例 2:50_000_000 个兰特数字(每个 10 位),516Mbytes,48_351_464 个不同的值:

$ shuf _1 |  sed 'N;s/\n/ /' > _11
Run Code Online (Sandbox Code Playgroud)

(以下数字不是很精确):

????????????????????????????????????????????????????
?        ? Sol1   ? Sol2           ? Sol3   ? Sol4 ?
?        ? sort...? perl DB        ? awk    ? perl ?
????????????????????????????????????????????????????
? case 1 ? 6m15   ? 6m17           ? 0m28   ? 0m28 ?
????????????????????????????????????????????????????
? case 2 ? 11m15  ? 81m44          ? out of memory ?
????????????????????????????????????????????????????
? case 2 ?        ? 5m54 /cache=2G ?        ?      ?
????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

带缓存的 sol2 是:

use DB_File;
use Fcntl ;

$DB_HASH->{'cachesize'} = 2000_000_000;
tie %h, 'DB_File', "_my.db", O_RDWR|O_CREAT|O_TRUNC, 0640, $DB_HASH;

while(<>){ not $h{$_} and print and $h{$_}=1 }
Run Code Online (Sandbox Code Playgroud)

排序也可以优化添加缓存大小选项(未完成)。

一个快速结论:

  • sort 是一个很棒的命令!