在linux中基于文件内的文本拆分大文件的最快方法

时间:2013-02-03 21:01:18

标签: linux bash sed awk

我有一个包含10年数据的大文件。我想将其拆分为每个包含1年数据的文件。

文件中的数据采用以下格式:

GBPUSD,20100201,000200,1.5969,1.5969,1.5967,1.5967,4 GBPUSD,20100201,000300,1.5967,1.5967,1.5960,1.5962,4

字符8-11包含年份。我想用它作为文件名,最后是.txt。所以2011.txt,2012.txt等

该文件包含大约400万行。

我正在使用Ubuntu Linux

3 个答案:

答案 0 :(得分:6)

这是使用awk的一种方式:

awk '{ print > substr($0,8,4) ".txt" }' file

如果第一个字段的长度可能不同,您可能更喜欢:

awk -F, '{ print > substr($2,0,4) ".txt" }' file

答案 1 :(得分:0)

我认为这应该来自命令行:

YEARS=`cat FILE | sed -e 's/^.......//' -e 's/\(....\).*$/\1/' | sort | uniq` ; for Y in $YEARS ; do echo Processing $Y... ; egrep '^.......'$Y FILE > $Y.txt ; done

答案 2 :(得分:0)

最好通读一次文件,并将每一行写入应该去的文件。所以@steve使用AWK的解决方案很好。

您可以使用grep和相应的正则表达式来解决此问题:^.......2010只匹配年份位置2010的行。然后一个shell脚本可以循环多年并继续运行grep,如下所示:

for year in 2010 2011 2012; do
    grep "^.......$year" datafile > $year.txt
done

但它不优雅,因为它每年读取整个源文件一次。

这是一个与AWK一起使用的Python解决方案。

import sys

def next_line():
    if len(sys.argv) == 1:
        for line in sys.stdin:
            yield line
    else:
        for name in sys.argv[1:]:
            with open(name) as f:
                for line in f:
                    yield line


_open_files = {}
def output(fname, line):
    if fname not in _open_files:
        _open_files[fname] = open(fname, "w")
    _open_files[fname].write(line)


for line in next_line():
    year = line[7:11]
    fname = year + ".txt"
    output(fname, line)

AWK肯定会因为简洁而获胜。我必须实现函数next_line()来提供一个服务,依次提供每个文件的源行,如果你没有指定文件,则提供标准输入;有了AWK,你可以免费获得。我必须实现函数output(),让你只提供文件名和字符串并写出输出,但是使用AWK你可以免费获得。

如果您的问题不会变得更加复杂,您可以使用AWK解决方案,但如果您希望随着时间的推移添加更多的花里胡哨,Python解决方案可能会有所回报。 (这就是我喜欢Python的原因......一旦你有了它,无论你需要做什么,它都很容易扩展。)