首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >AWK处理文件花费了很长时间

AWK处理文件花费了很长时间
EN

Stack Overflow用户
提问于 2020-05-14 19:57:54
回答 2查看 466关注 0票数 3

我有一个很大的档案,里面有大约600万份记录。我需要根据前17个字符将这个文件块成更小的文件。因此,头17个字符相同的记录将被分组为一个同名的文件。

我为此使用的命令是:

代码语言:javascript
运行
复制
awk -v  FIELDWIDTHS="17"  '{print > $1".txt"}' $file_name

问题是,这是痛苦的缓慢。对于一个有800 K记录的文件,它大约需要一个小时才能完成。

样本输入如下:

代码语言:javascript
运行
复制
AAAAAAAAAAAAAAAAAAAAAAAAAAAA75838458
AAAAAAAAAAAAAAAAAAAAAAAAAAAA48234283
BBBBBBBBBBBBBBBBBBBBBBBBBBBB34723643
AAAAAAAAAAAAAAAAAAAAAAAAAAAA64734987
BBBBBBBBBBBBBBBBBBBBBBBBBBBB18741274
CCCCCCCCCCCCCCCCCCCCCCCCCCCC38123922

这个问题有更快的解决办法吗?

我读到perl也可以用来分割文件,但是我找不到像perl中的字段宽度这样的选项。

如有任何帮助,将不胜感激。

uname : Linux

bash-4.1美元超限-n 1024

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-05-14 21:59:00

代码语言:javascript
运行
复制
sort file |
awk '{out=substr($0,1,17)".txt"} out != prev{close(prev); prev=out} {print > out}'

业绩改进包括:

  1. 不引用任何字段,它允许awk只在输入的关键部分更改时才对输出文件名进行排序和更改输出文件名,从而使awk一次只使用一个输出文件,而不必管理可能有数千个输出文件的打开/关闭(

)。

而且它对所有的gawk都是可移植的,因为它没有使用gawk特有的扩展,比如FIELDWIDTHS。

如果每个输出文件中的行在排序后必须保留它们原来的相对顺序,那么应该是这样的(假设输入中没有空白,就像您提供的示例一样):

代码语言:javascript
运行
复制
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}'

借用@dawg的脚本后(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 -谢谢!)要生成他所拥有的相同类型的示例输入文件,下面是上面所述的时间:

代码语言:javascript
运行
复制
$ 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

对于@dawg,用于比较在同一台机器上运行的相同输入.在它运行了14+分钟之后,我就杀了它:

代码语言:javascript
运行
复制
$ 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
票数 2
EN

Stack Overflow用户

发布于 2020-05-14 21:12:59

我创建了这个表单的测试文件:

代码语言:javascript
运行
复制
% head file
SXXYTTLDCNKRTDIHE00004
QAMKKMCOUHJFSGFFA00001
XGHCCGLVASMIUMVHS00002
MICMHWQSJOKDVGJEO00005
AIDKSTWRVGNMQWCMQ00001
OZQDJAXYWTLXSKAUS00003
XBAUOLWLFVVQSBKKC00005
ULRVFNKZIOWBUGGVL00004
NIXDTLKKNBSUMITOA00003
WVEEALFWNCNLWRAYR00001
% wc -l file
  600000 file

例如,12万个不同的17个字母前缀与01 - 05按随机顺序追加。

如果您想要一个自己的版本,下面是测试脚本:

代码语言:javascript
运行
复制
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

如果我运行这个:

代码语言:javascript
运行
复制
% time awk -v  FIELDWIDTHS="17"  '{print > $1".txt"}' file

大概15分钟后我就放弃了。

你可以这样做:

代码语言:javascript
运行
复制
% time awk -v  FIELDWIDTHS="17"  '{of=$1 ".txt"; if (of in seen){ print >>of } else {print >of; seen[of]; } close(of);}' file

您询问了Perl,下面是Perl中的一个类似的程序,速度相当快:

代码语言:javascript
运行
复制
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与以下内容进行比较的小脚本:

代码语言:javascript
运行
复制
#!/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}'

其中的指纹:

代码语言:javascript
运行
复制
   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
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61806335

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档