用bash在一个巨大的文件中获取一行

时间:2010-05-08 12:32:20

标签: bash

如何在3 gig文本文件中获取特定行。所有的行都有:

  • 长度相同,
  • \n分隔。

我需要能够按需获得任何一条线。

如何做到这一点?只需返回一行。

6 个答案:

答案 0 :(得分:21)

如果所有行都具有相同的长度,那么到目前为止最好的方法是使用dd(1)并给它一个跳过参数。

让块大小为每行的长度(包括换行符),然后你可以这样做:

$ dd if=filename bs=<line-length> skip=<line_no - 1> count=1 2>/dev/null

我们的想法是寻找过去所有前一行(skip=<line_no - 1>)并阅读一行(count=1)。由于块大小设置为行长度(bs=<line-length>),因此每个块实际上是一行。重定向stderr,这样你就不会在最后得到烦人的统计数据。

这应该比通过程序读取所有线之前将线路流式传输更高效,然后将它们扔掉,因为dd会在文件中寻找您想要的位置并读取只有一行数据来自文件。

答案 1 :(得分:15)

head -10 file | tail -1返回第10行可能会很慢。

来自here

# print line number 52 
sed -n '52p' # method 1 
sed '52!d' # method 2 
sed '52q;d' # method 3, efficient on large files

答案 2 :(得分:3)

如果它不是一个固定记录长度的文件而且你没有在线路上开始做某种索引,那么你最好的选择就是使用:

head -n N filespec | tail -1

其中N是您想要的行号。

不幸的是,对于3Gb文件来说这不是最好的代码片段,但有很多方法可以让它更好。

如果文件不经常更改,您可能需要考虑将其编入索引。我的意思是让另一个文件,其中的行偏移作为固定长度记录。

所以文件:

0000000000
0000000017
0000000092
0000001023

会为您提供快速查找每一行的方法。只需将所需的行号乘以索引记录大小,然后在索引文件中查找。

然后使用该位置的值在主文件中搜索,以便您可以读取直到下一个换行符。

因此,对于第3行,您将在索引文件中寻找33(索引记录长度为10个字符加上换行符的一个字符)。读取那里的值0000000092,将为您提供用于主文件的偏移量。

当然,如果文件经常更改,那就没那么有用了,但是,如果你可以控制在附加内容时会发生什么,你仍然可以有效地为索引添加偏移量。如果控制它,那么只要索引的最后修改日期早于主文件的日期,就必须重新编制索引。


并且,根据您的更新:

  

更新:如果重要,所有行都有相同的长度。

使用额外的信息,您不需要索引 - 您可以通过将记录长度乘以记录长度(假设值适合您的数据类型),立即寻找主文件中的正确位置

类似于伪代码:

def getline(fhandle,reclen,recnum):
    seek to position reclen*recnum for file fhandle.
    read reclen characters into buffer.
    return buffer.

答案 3 :(得分:2)

awk替代方案,其中3是行号。

awk 'NR == 3 {print; exit}' file.txt

答案 4 :(得分:2)

qsed一起使用,以便在打印完专线后停止搜索。

sed -n '11723{p;q}' filename

Python(最小错误检查):

#!/usr/bin/env python
import sys

# by Dennis Williamson - 2010-05-08
# for http://stackoverflow.com/questions/2794049/getting-one-line-in-a-huge-file-with-bash

# seeks the requested line in a file with a fixed line length

# Usage: ./lineseek.py LINE FILE

# Example: ./lineseek 11723 data.txt

EXIT_SUCCESS      = 0
EXIT_NOT_FOUND    = 1
EXIT_OPT_ERR      = 2
EXIT_FILE_ERR     = 3
EXIT_DATA_ERR     = 4

# could use a try block here
seekline = int(sys.argv[1])

file = sys.argv[2]

try:
    if file == '-':
        handle = sys.stdin
        size = 0
    else:
        handle = open(file,'r')
except IOError as e:
    print >> sys.stderr, ("File Open Error")
    exit(EXIT_FILE_ERR)

try:
    line = handle.readline()
    lineend = handle.tell()
    linelen = len(line)
except IOError as e:
    print >> sys.stderr, ("File I/O Error")
    exit(EXIT_FILE_ERR)

# it would be really weird if this happened
if lineend != linelen:
    print >> sys.stderr, ("Line length inconsistent")
    exit(EXIT_DATA_ERR)

handle.seek(linelen * (seekline - 1))

try:
    line = handle.readline()
except IOError as e:
    print >> sys.stderr, ("File I/O Error")
    exit(EXIT_FILE_ERR)

if len(line) != linelen:
    print >> sys.stderr, ("Line length inconsistent")
    exit(EXIT_DATA_ERR)

print(line)

参数验证应该更好,并且还有许多其他改进的空间。

答案 5 :(得分:1)

快速perl one衬垫也适用于此......

$ perl -ne 'if (YOURLINENUMBER..YOURLINENUMBER) {print $_; last;}' /path/to/your/file