如何加快grep / awk命令?

时间:2019-05-28 02:22:36

标签: linux performance awk grep

我要处理文本文件(> 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

3 个答案:

答案 0 :(得分:3)

  

如何加快grep / awk命令的速度?

您确定grepawk是您感觉迟钝的元凶吗?您知道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