我要处理文本文件(> 300 GB),并将其拆分为小文本文件(〜1 GB)。我想加快grep / awk命令的速度。
我需要grep在b列上有值的行,这是我的方法:
# method 1:
awk -F',' '$2 ~ /a/ { print }' input
# method 2:
grep -e ".a" < inpuy
两种方式每个文件花费1分钟。那么如何加快此操作呢?
输入文件示例:
a,b,c,d
1,4a337485,2,54
4,2a4645647,4,56
6,5a3489556,3,22
9,,3,12
10,0,34,45
24,4a83944,3,22
45,,435,34
预期的输出文件:
a,b,c,d
1,4a337485,2,54
4,2a4645647,4,56
6,5a3489556,3,22
24,4a83944,3,22
答案 0 :(得分:3)
如何加快grep / awk命令的速度?
您确定grep
或awk
是您感觉迟钝的元凶吗?您知道cut(1)或sed(1)吗?您是否已对在数据上运行wc(1)的时间进行了基准测试?文本I / O可能要花费很多时间。
请基准测试几次,并使用time(1)基准测试程序。
我有一个高端Debian台式机(带有AMD 2970WX,64Gb RAM,1TB的SSD系统磁盘,多TB的7200RPM SATA数据磁盘),并且仅在25GB的文件上运行wc
(有些{{1 }}归档文件)位于硬盘上需要10分钟以上的时间(以*.tar.xz
来衡量),而time
通过读取该文件正在做一些真正简单的文本处理>依次,因此在相同数据上的运行速度应比wc
(但令我惊讶的是没有!)或grep
快:
awk
和(使用 same 文件上的wc /big/basile/backup.tar.xz 640.14s user 4.58s system 99% cpu 10:49.92 total
来计数grep
的出现次数)
a
只需巧妙地写 (使用有效的 O(log n) time complexity data structures:{{3} }或red-black trees等…)使用C或C ++或Ocaml或其他大多数良好语言和实现的等效程序。或购买更多RAM以增加hash tables。或购买page cache来保存您的数据。并且多次重复测试(由于页面缓存)。
使用300Gb的纯文本文件可能不是最好的方法。 拥有巨大的文本文件通常是 错误,一旦您需要处理几次相同的数据,这很可能是错误的。您最好以某种方式SSD。.
如果您对相同数据文件重复执行相同 grep -c a /big/basile/backup.tar.xz 38.30s user 7.60s system 33% cpu 2:17.06 total
搜索或grep
,则请考虑使用pre-process (另请参见 sqlite答案),甚至是一些this真实的other(例如,使用relational database或一些其他好的RDBMS)进行存储,然后处理您的原始数据。
因此,一种可行的方法(如果您有足够的磁盘空间)可能是编写一些程序(用C,Python,Ocaml等),由原始数据填充,并填充一些awk
数据库。一定要有聪明的PostGreSQL并花时间进行足够的database indexes设计,知道database schema。
答案 1 :(得分:2)
使用mawk,避免使用正则表达式,然后执行以下操作:
$ mawk -F, '$2!=""' file
a,b,c,d
1,4a337485,2,54
4,2a4645647,4,56
6,5a3489556,3,22
10,0,34,45
24,4a83944,3,22
让我们知道花费了多长时间。
我根据结果对1000万条数据进行了一些测试:使用mawk和regex:
GNU awk和正则表达式:
$ time gawk -F, '$2~/a/' file > /dev/null
real 0m7.494s
user 0m7.440s
sys 0m0.052s
GNU awk,没有正则表达式:
$ time gawk -F, '$2!=""' file >/dev/null
real 0m9.330s
user 0m9.276s
sys 0m0.052s
mawk,没有正则表达式:
$ time mawk -F, '$2!=""' file >/dev/null
real 0m4.961s
user 0m4.904s
sys 0m0.060s
mawk和正则表达式:
$ time mawk -F, '$2~/a/' file > /dev/null
real 0m3.672s
user 0m3.600s
sys 0m0.068s
答案 2 :(得分:0)
我怀疑您的真正问题是您反复调用awk(可能是在循环中),每组$ 2的值一次,并每次生成一个输出文件,例如:
awk -F, '$2==""' input > novals
awk -F, '$2!=""' input > yesvals
etc.
不要这样做,因为它效率很低,因为它在每次迭代时都读取整个文件。改为这样做:
awk '{out=($2=="" ? "novals" : "yesvals")} {print > out}' input
这将通过调用awk创建所有输出文件。一旦超过15个输出文件,将需要GNU awk对打开的文件描述符进行内部处理,或者在$ 2更改时需要添加close(out)
,并使用>>
而不是>
:< / p>
awk '$2!=prev{close(out); out=($2=="" ? "novals" : "yesvals"); prev=$2} {print >> out}' input
,如果您首先使用来对输入文件进行排序,则效率会更高(如果您关心为唯一的$ 2值保留输入顺序,则需要对-s
进行GNU排序以获得稳定的排序):
sort -t, -k2,2 -s