首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用shell打印特定行最快的方法是什么?

使用shell打印特定行最快的方法是什么?
EN

Stack Overflow用户
提问于 2013-04-16 12:06:34
回答 4查看 394关注 0票数 2

我有一个有5000万行的文件,我必须从其中随机抽取1000行。

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

代码语言:javascript
运行
复制
sed -n "$random{p;q}" file  

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

所以我想我应该优化打印的特定线速。

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

代码语言:javascript
运行
复制
sed -n "$line{p;q}" file

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

head -$line file | tail -1

打印一行代码只需要5-6秒,全部都是slow...cost。

在shell中有没有其他打印特定行的方法?或者python,perl可以比shell更快?或者我解决这个问题的方式是错误的?

迭代1000个随机数,每次使用shell一次,可能会生成1000次io operations.Maybe,我应该先使用一个数组来保存随机数,然后迭代文件一次。

代码语言:javascript
运行
复制
random_array=()

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

好吧,我将以这种方式进行测试,并在以后粘贴结果

EN

回答 4

Stack Overflow用户

发布于 2013-04-17 00:04:11

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

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

代码语言:javascript
运行
复制
#!/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散列。

票数 2
EN

Stack Overflow用户

发布于 2013-04-16 13:44:00

按照文件中行的顺序,不包括内存中的所有行:

代码语言:javascript
运行
复制
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
票数 1
EN

Stack Overflow用户

发布于 2013-04-16 14:14:21

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

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

  1. 一次性预先计算文件中的行偏移量,然后使用lseek查找并打印它们。您可以每隔100或1000行偏移量存储一次,以预先保存space.
  2. Generate的整个行号列表,并在一次遍历文件时收集这些行。然后把它们打印出来。(如果您希望行的顺序是随机的,则不能按原样打印)。

这两种方法在shell中都很难做到。对于仅适用于shell的解决方案,请尝试devnull的建议shuf。但是如果不是1,你会希望使用1000:

代码语言:javascript
运行
复制
shuf -n 1000 file
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16028610

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档