哪个是用shell打印特定行的最快方法?

时间:2013-04-16 04:06:34

标签: linux shell

我有一个包含5000万行的文件,我必须随机输出1000行。

首先,我创建了1000个随机数;然后我用

sed -n "$random{p;q}" file  

它真的很慢;一行输出至少需要5-6秒。

所以我认为我应该优化打印特定的线速度。

我们有很多方法可以打印特定的行:

sed -n "$line{p;q}" file

awk "NR==$line{print}" file

head -$line file | tail -1

一切都很慢......打印特定行需要大约5-6秒。

shell中是否还有其他方法可以打印特定的行?或者python,perl可以比shell快吗?或者我解决这个问题的方法错了?

---------------------------------------- SPLIT ------ ----------------------------------------

迭代1000个随机数,每次使用shell一次,可以生成1000次io操作。也许我应该先使用数组保存随机数并迭代文件一次。

random_array=()

awk '{if ( NR in $random_array ) print;}' file

好吧,我会以这种方式测试并稍后粘贴结果

4 个答案:

答案 0 :(得分:2)

为避免读取整个文件,您可以获取文件的大小,然后生成0到该数字之间的1000个偏移的列表。这些通常是位于一行中间的位置,但您可以阅读下一个换行符,然后阅读并打印以下行。但是,这会对文件的第一行引入偏差。如果您对平均线长度进行了估计,则可以从生成的偏移量中减去该数字(任何负面结果都意味着从偏移量0读取和打印。)

这是一个概念的快速证明。为了便于说明,我假设平均线长约为75个字符。这也会影响公平性(选择长线后的线的可能性更高)。最后一行的处理也不公平;如果它短于75个字符,则永远不会被选中(!) - 您可以尝试通过计算实际读取的行的实际平均线长来解决这个问题,但我将其留作练习,以便保持这个例子相当紧凑。

#!/usr/bin/perl

use strict;
use warnings;

use Fcntl (qw(SEEK_SET SEEK_CUR SEEK_END));

my $n = (defined @ARGV ? shift @ARGV : '--help');
die "Syntax: $0 number file\n" unless @ARGV == 1 and $n =~ m/^[0-9]+$/;

open (F, "<", $ARGV[0]) or die "$0: Could not open $ARGV[0]: $!\n";

seek (F, 0, SEEK_END) or die "$0: Could not SEEK_END $ARGV[0]: $!\n";
my $max = tell(F);

my %seen;
for (my $i=0; $i < $n; ++$i)
{
    my $offset = int(rand($max))-75;
    my $first = 0;
    if ($offset < 0)
    {
        $offset = 0;
        $first = 1;
    }
    seek (F, $offset, SEEK_SET)
        or die "$0: Could not SEEK_SET $ARGV[0]: $!\n";
    <F> unless $first;
    redo if eof (F);   # Cheap trick, just retry if at eof
    redo if $seen{tell(F)}++;
    print scalar(<F>);
}

我添加了代码以避免重复;这是%seen哈希。

答案 1 :(得分:1)

按文件中的行顺序,内存中没有所有行:

awk '
  NR==FNR { next }
  FNR==1{
    srand;
    n=NR-1
    for(i=1; i<=1000; i++) {
      line=0
      while(!line || line in A) line=int(rand*n)+1
      A[line]
    }
  } 
  FNR in A
' infile infile

答案 2 :(得分:0)

无论您使用哪种工具,找到这些线都有固有的成本。实质上,您需要每次遍历该大文件,查找并计算换行符号。

我可以看到两种解决方案:

  1. 一次性预先计算文件中的行偏移量,然后使用lseek查找打印件。您可以存储每个第100或第1000行偏移以节省空间。

  2. 预先生成整个行号列表,并在文件中一次性收集行。然后打印出来。 (如果您希望线条的顺序是随机的,则无法打印出来。)

  3. 其中任何一个在shell中都很难做到。对于仅限shell的解决方案,请尝试devnull的建议shuf。但不是1,你想要使用1000:

    shuf -n 1000 file
    

答案 3 :(得分:0)

如果您只想要更大规模数据文件中的特定行,则会根据您的请求增加成本。如果您的文件在一段时间(一周或更长时间)内不可变,则需要进行预处理,只有一个解决方案可以解决您的问题:

  1. 使用相同的行
  2. 将文件拆分为更小的文件
  3. 将每个文件粘贴到一个文件中;之后,链接1将包含1 1 + n 1 + 2n信息的信息
  4. 需要一个用于计算直线的外壳。
  5. 如您所知,以上只是一种方法。