我想用-f来匹配长列表(10,000)模式的grep。 原来,grep不喜欢这个(谁知道?)。 一天之后,它没有产生任何东西。 较小的清单几乎是瞬间工作的。
我想我可能会分开我的长单,做几次。 任何想法模式列表的最大长度是多less?
另外,我对unix还是个新手。 可选方法是受欢迎的。 模式列表或search项目是在一个纯文本文件中,每行一个。
感谢大家的指导。
我大约有同样的问题。 在900万行文件中搜索400万个模式。 看起来像是RAM的问题。 所以我得到了这个整齐的小工作,可能比分裂和加入慢,但它只需要这一行。
while read line; do grep $line fileToSearchIn;done < patternFile
我需要使用的工作,因为-F
标志是没有解决方案,大文件…
编辑:这似乎是很慢的大文件。 经过一些更多的研究,我发现了“faSomeRecords”以及Kent NGS-editing-Tools中的其他很棒的工具
我通过从550万条记录文件中提取200万个fasta-rec来自己尝试。 接近约。 30秒..
干杯
编辑: 直接下载链接
从评论看来,你匹配的模式是固定的字符串。 如果是这样的话,你一定要用-F
。 这将大大增加匹配的速度。 (使用479,000个字符串匹配输入文件和3行,使用-F
在中等功率的机器上需要1.5秒的时间,不使用-F
,同一台机器在几分钟后还没有完成。
这里是一个bash脚本,你可以在你的文件上运行(或者如果你愿意的话,你的文件的一个子集)。 它将把密钥文件分割成越来越大的块,并且为每个块尝试grep操作。 操作是定时的 – 现在我正在计算每个grep操作,以及处理所有子表达式的总时间。 输出是在几秒钟 – 有一些努力,你可以得到毫秒,但与你遇到的问题不太可能你需要的粒度。 用窗体的命令在终端窗口中运行脚本
./timeScript keyFile textFile 100 > outputFile
这将运行脚本,使用keyFile作为存储搜索关键字的文件,textFile作为您要查找关键字的文件,使用100作为初始块大小。 在每个循环中,块大小将会加倍。
在第二个终端中,运行命令
tail -f outputFile
这将跟踪你的其他进程的输出到文件outputFile
我建议您打开第三个终端窗口,并在该窗口中运行top
。 你将能够看到你的进程有多少内存和CPU – 再次,如果你看到大量的内存消耗,它会给你提示,事情进展不顺利。
这应该让你找出什么时候事情开始放缓 – 这是你的问题的答案。 我不认为有一个“神奇的数字” – 这可能取决于你的机器,特别是文件大小和内存的数量。
你可以把脚本的输出结果通过一个grep:
grep entire outputFile
最后只是总结 – 块的大小和时间,例如
Time for processing entire file with blocksize 800: 4 seconds
如果您将这些数字相互对照(或简单地检查数字),您会看到算法何时优化,何时减慢。
这里是代码:我没有做广泛的错误检查,但它似乎为我工作。 很显然,在你的最终解决方案中,你需要用grep的输出做一些事情(而不是将它输送到wc -l
,我只是想看看有多少行被匹配)。
#!/bin/bash # script to look at difference in timing # when grepping a file with a large number of expressions # assume first argument = name of file with list of expressions # second argument = name of file to check # optional third argument = initial block size (default 100) # # split f1 into chunks of 1, 2, 4, 8... expressions at a time # and print out how long it took to process all the lines in f2 if (($# < 2 )); then echo Warning: need at leasttwo parameters. echo Usage: timeScript keyFile searchFile [initial blocksize] exit 0 fi f1_linecount=`cat $1 | wc -l` echo linecount of file1 is $f1_linecount f2_linecount=`cat $2 | wc -l` echo linecount of file2 is $f2_linecount echo if (($# < 3 )); then blockLength=100 else blockLength=$3 fi while (($blockLength < f1_linecount)) do echo Using blocks of $blockLength #split is a built in command that splits the file # -l tells it to break after $blockLength lines # and the block$blockLength parameter is a prefix for the file split -l $blockLength $1 block$blockLength Tstart="$(date +%s)" Tbefore=$Tstart for fn in block* do echo "grep -f $fn $2 | wc -l" echo number of lines matched: `grep -f $fn $2 | wc -l` Tnow="$(($(date +%s)))" echo Time taken: $(($Tnow - $Tbefore)) s Tbefore=$Tnow done echo Time for processing entire file with blocksize $blockLength: $(($Tnow - $Tstart)) seconds blockLength=$((2*$blockLength)) # remove the split files - no longer needed rm block* echo block length is now $blockLength and f1 linecount is $f1_linecount done exit 0
你当然可以试一试,看看你是否得到了更好的结果,但是在任何大小的文件上做任何事情都是很多的工作。 你没有提供任何关于你的问题的细节,但是如果你有10k个模式,我会试着去考虑是否有办法把它们推广到更少的正则表达式中。
这是一个perl脚本“match_many.pl”,它解决了“大量密钥与大量记录”问题的一个非常常见的子集。 键从标准输入接受一行。 两个命令行参数是要搜索的文件的名称和必须与键匹配的字段(空格分隔)。 原始问题的这个子集可以快速解决,因为记录中的匹配位置(如果有的话)提前知道,而且键总是对应于记录中的整个字段。 在一个典型的情况下,它搜索了9400265个具有42899个键的记录,匹配了42401个键,并在41s中发出了1831944条记录。 更一般的情况下,键可能出现在记录的任何部分的子字符串,这是一个更难的问题,这个脚本没有解决。 (如果键不包含空格,并且总是对应于整个单词,则脚本可以被修改以通过遍历每个记录的所有字段来处理该情况,而不是仅仅测试该空白,代价是以较慢的M次运行,其中M是找到匹配的平均字段号。)
#!/usr/bin/perl -w use strict; use warnings; my $kcount; my ($infile,$test_field) = @ARGV; if(!defined($infile) || "$infile" eq "" || !defined($test_field) || ($test_field <= 0)){ die "syntax: match_many.pl infile field" } my %keys; # hash of keys $test_field--; # external range (1,N) to internal range (0,N-1) $kcount=0; while(<STDIN>) { my $line = $_; chomp($line); $keys {$line} = 1; $kcount++ } print STDERR "keys read: $kcount\n"; my $records = 0; my $emitted = 0; open(INFILE, $infile ) or die "Could not open $infile"; while(<INFILE>) { if(substr($_,0,1) =~ /#/){ #skip comment lines next; } my $line = $_; chomp($line); $line =~ s/^\s+//; my @fields = split(/\s+/, $line); if(exists($keys{$fields[$test_field]})){ print STDOUT "$line\n"; $emitted++; $keys{$fields[$test_field]}++; } $records++; } $kcount=0; while( my( $key, $value ) = each %keys ){ if($value > 1){ $kcount++; } } close(INFILE); print STDERR "records read: $records, emitted: $emitted; keys matched: $kcount\n"; exit;