AWK处理文件需要很长时间
我有一个大约600万条记录的大文件。我需要根据前17个字符将此文件分为更小的文件。因此,前17个字符相同的记录将被分组到具有相同名称的文件中 我用于此操作的命令是:AWK处理文件需要很长时间,awk,Awk,我有一个大约600万条记录的大文件。我需要根据前17个字符将此文件分为更小的文件。因此,前17个字符相同的记录将被分组到具有相同名称的文件中 我用于此操作的命令是: awk -v FIELDWIDTHS="17" '{print > $1".txt"}' $file_name 问题是,这是痛苦的缓慢。对于一个有800K条记录的文件,大约需要一个小时才能完成 样本输入为:- AAAAAAAAAAAAAAAAAAAAAAAAAAAA75838458 AAAAAAAAAAAAAAAAAAA
awk -v FIELDWIDTHS="17" '{print > $1".txt"}' $file_name
问题是,这是痛苦的缓慢。对于一个有800K条记录的文件,大约需要一个小时才能完成
样本输入为:-
AAAAAAAAAAAAAAAAAAAAAAAAAAAA75838458
AAAAAAAAAAAAAAAAAAAAAAAAAAAA48234283
BBBBBBBBBBBBBBBBBBBBBBBBBBBB34723643
AAAAAAAAAAAAAAAAAAAAAAAAAAAA64734987
BBBBBBBBBBBBBBBBBBBBBBBBBBBB18741274
CCCCCCCCCCCCCCCCCCCCCCCCCCCC38123922
这个问题有没有更快的解决方案
我读到perl也可以用来分割文件,但在perl中找不到像fieldwidths这样的选项
任何帮助都将不胜感激
uname:Linux
bash-4.1$ulimit-n
1024我创建了此表单的测试文件:
% head file
SXXYTTLDCNKRTDIHE00004
QAMKKMCOUHJFSGFFA00001
XGHCCGLVASMIUMVHS00002
MICMHWQSJOKDVGJEO00005
AIDKSTWRVGNMQWCMQ00001
OZQDJAXYWTLXSKAUS00003
XBAUOLWLFVVQSBKKC00005
ULRVFNKZIOWBUGGVL00004
NIXDTLKKNBSUMITOA00003
WVEEALFWNCNLWRAYR00001
% wc -l file
600000 file
也就是说,有120000个不同的17个字母的前缀,以随机顺序追加01-05
如果您想要自己的版本,以下是测试脚本:
perl -le 'for (1..120000) {print map { (q(A)..q(Z))[rand(26)] } 1 .. 17} ' | awk '{for (i=1; i<6; i++) printf ("%s%05i\n", $0, i)}' | awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}'| sort -n | cut -c8- > /tmp/test/file
大约15分钟后我就放弃了
您可以这样做:
% time awk -v FIELDWIDTHS="17" '{of=$1 ".txt"; if (of in seen){ print >>of } else {print >of; seen[of]; } close(of);}' file
您询问了Perl,这里有一个类似的Perl程序,速度非常快:
perl -lne '$p=unpack("A17", $_); if ($seen{$p}) { open(fh, ">>", "$p.txt"); print fh $_;} else { open(fh, ">", "$p.txt"); $seen{$p}++; }close fh' file
下面是一个将Ed的awk与以下内容进行比较的小脚本:
#!/bin/bash
# run this in a clean directory Luke!
perl -le 'for (1..12000) {print map { (q(A)..q(Z))[rand(26)] } 1 .. 17} '
| awk '{for (i=1; i<6; i++) printf ("%s%05i\n", $0, i)}'
| awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}'
| sort -n
| cut -c8- > file.txt
wc -l file.txt
#awk -v FIELDWIDTHS="17" '{cnt[$1]++} END{for (e in cnt) print e, cnt[e]}' file
echo "abd awk"
time awk -v FIELDWIDTHS="17" '{of=$1 ".txt"; if (of in seen){ print >>of } else {print >of; seen[of]; } close(of);}' file.txt
echo "abd Perl"
time perl -lne '$p=unpack("A17", $_); if ($seen{$p}) { open(fh, ">>", "$p.txt"); print fh $_;} else { open(fh, ">", "$p.txt"); $seen{$p}++; }close fh' file.txt
echo "Ed 1"
time sort file.txt |
awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'
echo "Ed 2"
time sort file.txt | awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'
echo "Ed 3"
time awk '{print substr($0,1,17)".txt", NR, $0}' file.txt | sort -k1,1 -k2,2n | awk '$1 != prev{close(prev); prev=$1} {print $3 > $1}'
业绩改进包括:
借用@dawg的脚本(
perl-le'for(1..120000){print map{(q(A)…q(Z))[rand(26)]}1..17}{for(i=1;ii如果所有记录都有唯一的前缀,我认为任何改进都不会对性能产生显著影响。有多少唯一的前缀?它可能更快(与直觉相反)首先根据前缀对文件进行排序,以便一次写入所有前缀文件。由于文件数量太多,您可能还会遇到性能问题……您的脚本生成了多少文件?请将ulimit-n
的输出和操作系统的名称添加到您的问题中。@dawg我们预计大约有5-6条记录共享相同的前缀..所以一个800K的记录文件生成了大约12000个更小的文件files@Cyrus:将uname和ulimit的输出添加到上述问题中。您是否介意共享您为创建测试输入文件而编写的脚本(或根据您的输入测试我答案中的2个脚本并发布结果)?我假设您正在进行第三次运行计时,以消除任何缓存影响。这不是我最漂亮的;-)。但我会补充答案。幸运的是,“漂亮”并不是一次性代码生成临时文件的目标,特别是如果它可以节省我们其他人为自己创建临时文件的时间:-).谢谢!你介意在你的盒子上测试我两个脚本的计时吗?我想在同一个盒子上用相同的输入发布我和你两个脚本的计时,以便进行比较,但在我的笔记本电脑上,你的脚本已经运行了几分钟,因此我失去了尝试更多次以避免缓存问题的意愿。完成。你的更快-)在我的机器上注意:它是一个16核的Mac Pro,在RAID 0中有6个SSD。不一定具有代表性。
#!/bin/bash
# run this in a clean directory Luke!
perl -le 'for (1..12000) {print map { (q(A)..q(Z))[rand(26)] } 1 .. 17} '
| awk '{for (i=1; i<6; i++) printf ("%s%05i\n", $0, i)}'
| awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}'
| sort -n
| cut -c8- > file.txt
wc -l file.txt
#awk -v FIELDWIDTHS="17" '{cnt[$1]++} END{for (e in cnt) print e, cnt[e]}' file
echo "abd awk"
time awk -v FIELDWIDTHS="17" '{of=$1 ".txt"; if (of in seen){ print >>of } else {print >of; seen[of]; } close(of);}' file.txt
echo "abd Perl"
time perl -lne '$p=unpack("A17", $_); if ($seen{$p}) { open(fh, ">>", "$p.txt"); print fh $_;} else { open(fh, ">", "$p.txt"); $seen{$p}++; }close fh' file.txt
echo "Ed 1"
time sort file.txt |
awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'
echo "Ed 2"
time sort file.txt | awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'
echo "Ed 3"
time awk '{print substr($0,1,17)".txt", NR, $0}' file.txt | sort -k1,1 -k2,2n | awk '$1 != prev{close(prev); prev=$1} {print $3 > $1}'
60000 file.txt
abd awk
real 0m3.058s
user 0m0.329s
sys 0m2.658s
abd Perl
real 0m3.091s
user 0m0.332s
sys 0m2.600s
Ed 1
real 0m1.158s
user 0m0.174s
sys 0m0.992s
Ed 2
real 0m1.069s
user 0m0.175s
sys 0m0.932s
Ed 3
real 0m1.174s
user 0m0.275s
sys 0m0.946s
sort file |
awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'
awk '{print substr($0,1,17)".txt", NR, $0}' file |
sort -k1,1 -k2,2n |
awk '$1 != prev{close(prev); prev=$1} {print $3 > $1}'
$ time sort ../file | awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'
real 0m45.709s
user 0m15.124s
sys 0m34.090s
$ time awk '{print substr($0,1,17)".txt", NR, $0}' ../file | sort -k1,1 -k2,2n | awk '$1 != prev{close(prev); prev=$1} {print $3 > $1}'
real 0m49.190s
user 0m11.170s
sys 0m34.046s
$ time awk -v FIELDWIDTHS="17" '{of=$1 ".txt"; if (of in seen){ print >>of } else {print >of; seen[of]; } close(of);}' ../file
real 14m23.473s
user 0m7.328s
sys 1m0.296s