你可以试试这个:
perl -F, -MDigest::MD5=md5 -lanE 'say unless $seen{ md5($F[4]) }++' < file.csv >unique_field5.txt
它将为每个唯一的field-5(例如$F[4])在内存中保存 16 字节长的 md5-digest。或者你可以使用
cut -d, -f5 csv | perl -MDigest::MD5=md5 -lnE 'say unless $seen{md5($_)}++'
同样的结果。
当然,现在 md5 在密码学上并不安全,但可能足以用于排序...当然,可以使用 sha1 或 sha256,只需使用 -MDigest::SHA=sha255。当然,sha-digests 更长 - 例如需要更多内存。
它与 cmets 中链接的 awk 类似,不同之处在于,这里用作哈希键而不是整个输入行,而只是 16byte 长 MD5 摘要。
编辑
因为我想知道性能,所以创建了这个测试用例:
# this perl create 400,000,000 records
# each 100 bytes + attached random number,
# total size of data 40GB.
# each invocation generates same data (srand(1))
# because the random number is between 0 - 50_000_000
# here is approx. 25% unique records.
gendata() {
perl -E '
BEGIN{ srand(1) }
say "x"x100, int(rand()*50_000_000) for 1..400_000_000
'
}
# the unique sorting - by digest
# also using Devel::Size perl module to get the final size of the data hold in the memory
# using md5
domd5() {
perl -MDigest::MD5=md5 -MDevel::Size=total_size -lnE '
say unless $seen{md5($_)}++;
END {
warn"total: " . total_size(\%seen);
}'
}
#using sha256
dosha256() {
perl -MDigest::SHA=sha256 -MDevel::Size=total_size -lnE '
say unless $seen{sha256($_)}++;
END {
warn"total: " . total_size(\%seen);
}'
}
#MAIN
time gendata | domd5 | wc -l
time gendata | dosha256 | wc -l
结果:
total: 5435239618 at -e line 4, <> line 400000000.
49983353
real 10m12,689s
user 12m43,714s
sys 0m29,069s
total: 6234973266 at -e line 4, <> line 400000000.
49983353
real 15m51,884s
user 18m23,900s
sys 0m29,485s
例如:
对于 md5
- 内存使用量:5,435,239,618 字节 - 例如大约 5.4 GB
- 唯一记录:49,983,353
- 运行时间:10 分钟
对于 sha256
- 内存使用量:6,234,973,266 字节 - 例如大约 6.2 GB
- 唯一记录:49,983,353
- 运行时间:16 分钟
相比之下,使用“常规”方法进行纯文本唯一搜索:
doplain() {
perl -MDevel::Size=total_size -lnE '
say unless $seen{$_}++;
END {
warn"total: " . total_size(\%seen);
}'
}
例如跑步:
time gendata | doplain | wc -l
结果:
- 内存使用量要大得多:10,022,600,682 - 我的 16GB RAM 笔记本开始大量交换(因为有 SSD,所以没什么大不了的 - 但仍然......)
- 唯一记录:49,983,353
- 运行时间:8:30 分钟
结果?
只需使用
cut -d, -f5 csv | perl -MDigest::MD5=md5 -lnE 'say unless $seen{md5($_)}++'
你应该足够快地获得独特的线条。