Ste*_*gin 5 bash command-line random-sample line-processing
如何n从无法放入内存的非常大的文件中获取随机行。
如果我可以在随机化之前或之后添加过滤器也很棒。
就我而言,规格是:
所以从文件中丢失几行不会是一个大问题,因为无论如何它们都有 1 万分之一的机会,但性能和资源消耗将是一个问题
在这样的限制因素下,下面的方法会更好。
为此,您需要一个可以在文件中查找的工具,例如perl.
use strict;
use warnings;
use Symbol;
use Fcntl qw( :seek O_RDONLY ) ;
my $seekdiff = 256; #e.g. from "rand_position-256" up to rand_positon+256
my($want, $filename) = @ARGV;
my $fd = gensym ;
sysopen($fd, $filename, O_RDONLY ) || die("Can't open $filename: $!");
binmode $fd;
my $endpos = sysseek( $fd, 0, SEEK_END ) or die("Can't seek: $!");
my $buffer;
my $cnt;
while($want > $cnt++) {
my $randpos = int(rand($endpos)); #random file position
my $seekpos = $randpos - $seekdiff; #start read here ($seekdiff chars before)
$seekpos = 0 if( $seekpos < 0 );
sysseek($fd, $seekpos, SEEK_SET); #seek to position
my $in_count = sysread($fd, $buffer, $seekdiff<<1); #read 2*seekdiff characters
my $rand_in_buff = ($randpos - $seekpos)-1; #the random positon in the buffer
my $linestart = rindex($buffer, "\n", $rand_in_buff) + 1; #find the begining of the line in the buffer
my $lineend = index $buffer, "\n", $linestart; #find the end of line in the buffer
my $the_line = substr $buffer, $linestart, $lineend < 0 ? 0 : $lineend-$linestart;
print "$the_line\n";
}
Run Code Online (Sandbox Code Playgroud)
将上述内容保存到某个文件中,例如“randlines.pl”并将其用作:
perl randlines.pl wanted_count_of_lines file_name
Run Code Online (Sandbox Code Playgroud)
例如
perl randlines.pl 10000 ./BIGFILE
Run Code Online (Sandbox Code Playgroud)
该脚本执行非常低级的 IO 操作,即非常快。(在我的笔记本上,从 10M 中选择 30k 行需要半秒)。
#!/bin/bash
#contents of bashScript.sh
file="$1";
lineCnt=$2;
filter="$3";
nfilter="$4";
echo "getting $lineCnt lines from $file matching '$filter' and not matching '$nfilter'" 1>&2;
totalLineCnt=$(cat "$file" | grep "$filter" | grep -v "$nfilter" | wc -l | grep -o '^[0-9]\+');
echo "filtered count : $totalLineCnt" 1>&2;
chances=$( echo "$lineCnt/$totalLineCnt" | bc -l );
echo "chances : $chances" 1>&2;
cat "$file" | awk 'BEGIN { srand() } rand() <= $chances { print; }' | grep "$filter" | grep -v "$nfilter" | head -"$lineCnt";
Run Code Online (Sandbox Code Playgroud)
获取 1000 个随机样本
bashScript.sh /path/to/largefile.txt 1000
Run Code Online (Sandbox Code Playgroud)
行有数字
bashScript.sh /path/to/largefile.txt 1000 "[0-9]"
Run Code Online (Sandbox Code Playgroud)
没有迈克和简
bashScript.sh /path/to/largefile.txt 1000 "[0-9]" "mike|jane"
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2831 次 |
| 最近记录: |