参考在网上找到的代码,没想到相差那么大,应该是grep比perl的模式匹配更快吧。
[gzhy@nearby stat]$ wc -l 1 234033 1[gzhy@nearby stat]$ perl 1.pl cost 1 secondszjtel : 32606[gzhy@nearby stat]$ perl 2.pl cost 111 secondszjtel : 326062.pl
#!/usr/bin/perlmy $time=time();open(file,"1");while(1.pl;){ chomp; if(m/:zjtel:/) { $zjtel++; }}close(file);$time=time()-$time;print "cost $time seconds\n";print "zjtel : $zjtel\n";
#!/usr/bin/perl$time=time();$count=`grep zjtel 1 | wc -l `;$time=time()-$time;print "cost $time seconds\n";print "zjtel : $count\n":
测试:在一个文件夹下有199个纯文本文件,要扫描265个关键字,分别用pattern-match
和grep两种方式进行扫描,统计扫描时间。结果:均查出6354行。
pattern-match:2173 seconds;
grep1: 888 seconds;
grep2: 193 seconds;
参考代码如下:
pattern-match:
use strict;use File::Basename;#在一个目录的文件文件中查找包含关键字的 <文件名> : <行数> : <行内容> my ($dir,$keywords)= @ARGV;my @filenames=glob "$dir*";open KEY,"<$keywords" or die "Can't open $keywords:$!";my @keywords=;close KEY;my $num_key=scalar @keywords;my @match_lines;my $time=time();foreach my $file(@filenames){ eval{ open FILE,"<$file" or die "Can't open $file:$!" }; if($@){ print $@; next; } $n=1; while my $line( 行内容> 行数> 文件名>){ chomp $line; foreach my $key(@keywords){ if($line=~m/$key/){ $context="$file:$n:$line\n"; push @match_lines,$context; } }$n++; } close(file);}open RS,">result_file_pattern";foreach(@match_lines){ print RS $_;}close RS;$time=time()-$time;print "Patter-match ($num_key keywords) end:$time seconds\n";
grep1: 分别扫每个keywords
use strict;use File::Basename;#在一个目录的文件文件中查找包含关键字的 <文件名> : <行数> : <行内容> my ($dir,$keywords)= @ARGV;my @filename=glob "$dir*";open KEY,"<$keywords" or die "Can't open $keywords";my @keywords=;close KEY;my $num_key=scalar @keywords;my @match_lines;my $time=time();foreach my $file(@filenames){ foreach $key(@keywords){ chomp $key; next unless ($key); my $m_keyword = "\\<$key\\>\|\[\^a-z\]$key\$\|\^$key\[\^a-z\]\|\[\^a-z\]$key\[\^a-z\]"; my @sub_match_lines eval{ @sub_match_lines=`grep -EnriIHs $m_keyword $file` or die "grep Error:$!" }; if($@}{ print "$@"; next; } push @match_lines,@sub_match_lines; }}open RS,">result_file_grep";foreach(@match_lines){ print RS $_;}close RS;$time=time()-$time;print "Grep ($num_key keywords) end : $time seconds\n";//如果直接将$context print到RS句柄和现在这种方式是否有区别? 行内容> 行数> 文件名>
grep2: 经265个keywords放在一个匹配字符串中扫描
use strict;use File::Basename;my ($dir,$keywords)= @ARGV;my @filenames=glob "$dir*";my $num=scalar @filenames;print $num;open KEY,"<$keywords" or die "Can't open $keywords";my $all_keys;my $i=0;foreach my $key(){ chomp $key; next unless($key); my $m_keyword = "\\<$key\\>\|\[\^a-z\]$key\$\|\^$key\[\^a-z\]\|\[\^a-z\]$key\[\^a-z\]"; if($i==0){ $all_keys.="$m_keyword"; $i=1; }else{ $all_keys.="\|$m_keyword"; }}close KEY;my @match_lines;my $time1=time();foreach my $file(@filenames){ chomp $file; print $file."\n"; my @sub_match_lines; eval{ my $grep ="grep -EnriIHs \"$all_keys\" $file"; @sub_match_lines=`$grep` or die "$grep Error:$!"; }; if($@){ print $@; next; } push @match_lines,@sub_match_lines;}open RS,">result_file_grep2";foreach(@match_lines){ print RS $_;}close RS;$time=time()-$time;print "Grep end:$time\n";
File::Basename模块:
File::Basename - Parse file paths into directory, filename and suffix.
File::Basename中常用的方法有fileparse, basename, dirname。fileparse方法会传回包含路经名称三个部份的串列。basename方法传回路经位置。basename方法传回档案名称。
($name,$path,$suffix) = fileparse($fullname,@suffixlist);
my $filename = fileparse("/foo/bar/baz.txt", qr/\Q.txt\E/);
目录句柄操作:
opendir,readdir,closedir
opendir只能返回目录下文件的不带路径的文件名。
opendir(DIRHANDLE,$dir) or die "Can't open $dir:$!";my @filenames=sort readdir(DIRHANDLE);closedir(DIRHANDLE);
Glob:
在shell中会将命令行的文件名模式扩展成所有匹配的文件名,这就成为globbing(文件名匹配模式)。
在Perl中通过glob操作符来实现。
my @all_files=glob "dir/*" ;#保存dir目录下所有文件名和目录,除了以点号开头的隐藏文件。
如:目录/file/下有a.txt,b.txt,和C文件夹,D文件夹;则glob "/file/*" ;则结果是/file/a.txt ;/file/b.txt ;/file/C;/file/D;
等同于my @all_files=<*>;
my @file=<FILE>;#表示读取文件内容;
my @file_dirs=<FILE/*>;#表示glob;
另外linux grep -r或-R可以递归遍历文件目录下的文件